1- import React , { useState , useEffect , useMemo , useRef } from 'react' ;
1+ import React , { useState , useEffect , useMemo , useRef , useCallback } from 'react' ;
22import styled from 'styled-components' ;
33import { useWebSocket , GitHubEvent } from './hooks/useWebSocket' ;
44import { useAudio } from './hooks/useAudio' ;
@@ -98,7 +98,6 @@ const MainArea = styled.div<{ $isOnline: boolean }>`
9898 filter: blur(100px);
9999 border-radius: 99999px;
100100 margin: auto;
101- transform: scale(0.8);
102101 background: conic-gradient(
103102 from 0deg,
104103 #90D1CA 0%,
@@ -182,8 +181,8 @@ const App: React.FC = () => {
182181 const [ volume , setVolumeState ] = useState ( 0.5 ) ;
183182 const [ orgRepoFilter , setOrgRepoFilter ] = useState ( '' ) ;
184183 const [ processedEvents , setProcessedEvents ] = useState < GitHubEvent [ ] > ( [ ] ) ;
185- const processedCountRef = useRef ( 0 ) ;
186- const eventQueueRef = useRef < GitHubEvent [ ] > ( [ ] ) ;
184+ const processedEventIdsRef = useRef < Set < string > > ( new Set ( ) ) ;
185+ const processingTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
187186
188187 // Parse org/repo filter into array
189188 const orgRepoFilterArray = useMemo ( ( ) => {
@@ -198,47 +197,76 @@ const App: React.FC = () => {
198197
199198 const { allSoundsLoaded, playSound, setVolume } = useAudio ( ) ;
200199
201- // Update eventQueue ref whenever eventQueue changes
202- useEffect ( ( ) => {
203- eventQueueRef . current = eventQueue ;
204- } , [ eventQueue ] ) ;
205-
206- // Process events from queue
207- useEffect ( ( ) => {
208- if ( ! showClickToPlay && allSoundsLoaded ) {
209- let isProcessing = true ;
200+ // Process events one at a time with proper delays (matching original implementation)
201+ const processNextEvent = useCallback ( ( ) => {
202+ if ( ! showClickToPlay && allSoundsLoaded && eventQueue . length > 0 ) {
203+ // Find the next unprocessed event using event_url as unique identifier
204+ const nextEvent = eventQueue . find ( event =>
205+ event . event_url && ! processedEventIdsRef . current . has ( event . event_url )
206+ ) ;
210207
211- const playFromQueue = ( ) => {
212- if ( ! isProcessing ) return ;
208+ if ( nextEvent && nextEvent . actor ?. display_login && nextEvent . event_url ) {
209+ console . log ( `Processing event: ${ nextEvent . type } by ${ nextEvent . actor . display_login } (URL: ${ nextEvent . event_url . slice ( - 8 ) } )` ) ;
213210
214- // Get next unprocessed event from queue using ref
215- if ( processedCountRef . current < eventQueueRef . current . length ) {
216- const event = eventQueueRef . current [ processedCountRef . current ] ;
217- processedCountRef . current ++ ;
218-
219- if ( event && event . actor ?. display_login ) {
220- const size = event . actor . display_login . length * 1.1 ;
221- playSound ( size , event . type ) ;
222- setProcessedEvents ( prev => [ ...prev , event ] ) ;
223- }
224- }
211+ // Mark as processed immediately
212+ processedEventIdsRef . current . add ( nextEvent . event_url ) ;
225213
226- // Schedule next processing with random delay (500-1500ms)
227- setTimeout ( playFromQueue , Math . floor ( Math . random ( ) * 1000 ) + 500 ) ;
228- } ;
214+ // Play sound and add to visualization
215+ const size = nextEvent . actor . display_login . length * 1.1 ;
216+ playSound ( size , nextEvent . type ) ;
217+ setProcessedEvents ( prev => {
218+ const newEvents = [ ...prev , nextEvent ] ;
219+ // Keep only the last 100 processed events to prevent memory issues
220+ return newEvents . slice ( - 100 ) ;
221+ } ) ;
222+
223+ console . log ( `Processed count: ${ processedEventIdsRef . current . size } , Queue length: ${ eventQueue . length } ` ) ;
224+ } else if ( eventQueue . length > 0 ) {
225+ console . log ( `No new events to process (queue: ${ eventQueue . length } , processed: ${ processedEventIdsRef . current . size } )` ) ;
226+ }
229227
230- // Start processing after initial random delay
231- setTimeout ( playFromQueue , Math . floor ( Math . random ( ) * 1000 ) ) ;
228+ // Clean up the processed IDs set if it gets too large
229+ if ( processedEventIdsRef . current . size > 200 ) {
230+ console . log ( `Cleaning up processed URLs set (was ${ processedEventIdsRef . current . size } )` ) ;
231+ // Keep only the most recent event URLs from the current queue
232+ const recentUrls = new Set < string > ( ) ;
233+ eventQueue . slice ( - 100 ) . forEach ( event => {
234+ if ( event . event_url ) recentUrls . add ( event . event_url ) ;
235+ } ) ;
236+ processedEventIdsRef . current = recentUrls ;
237+ console . log ( `Cleaned up to ${ processedEventIdsRef . current . size } URLs` ) ;
238+ }
239+ }
240+
241+ // Schedule next processing cycle with original timing: 500-1500ms delay
242+ const delay = Math . floor ( Math . random ( ) * 1000 ) + 500 ;
243+ processingTimeoutRef . current = setTimeout ( processNextEvent , delay ) ;
244+ } , [ showClickToPlay , allSoundsLoaded , eventQueue , playSound ] ) ;
245+
246+ // Start the processing loop when conditions are met
247+ useEffect ( ( ) => {
248+ if ( ! showClickToPlay && allSoundsLoaded ) {
249+ // Clear any existing timeout
250+ if ( processingTimeoutRef . current ) {
251+ clearTimeout ( processingTimeoutRef . current ) ;
252+ }
253+
254+ // Start processing with initial delay
255+ const initialDelay = Math . floor ( Math . random ( ) * 1000 ) + 500 ;
256+ processingTimeoutRef . current = setTimeout ( processNextEvent , initialDelay ) ;
232257
233258 return ( ) => {
234- isProcessing = false ;
259+ if ( processingTimeoutRef . current ) {
260+ clearTimeout ( processingTimeoutRef . current ) ;
261+ }
235262 } ;
236263 }
237- } , [ showClickToPlay , allSoundsLoaded , playSound ] ) ;
264+ } , [ showClickToPlay , allSoundsLoaded , processNextEvent ] ) ;
238265
239- // Reset processed count when filter changes
266+ // Clear processed events when filter changes
240267 useEffect ( ( ) => {
241- processedCountRef . current = 0 ;
268+ setProcessedEvents ( [ ] ) ;
269+ processedEventIdsRef . current . clear ( ) ;
242270 } , [ orgRepoFilter ] ) ;
243271
244272 const handlePlayButtonClick = ( ) => {
0 commit comments