@@ -29,14 +29,37 @@ export class QueueManager {
2929 Hooks . on ( 'youtubeDJ.queueAdd' , this . onQueueAdd . bind ( this ) ) ;
3030 Hooks . on ( 'youtubeDJ.queueRemove' , this . onQueueRemove . bind ( this ) ) ;
3131 Hooks . on ( 'youtubeDJ.queueUpdate' , this . onQueueUpdate . bind ( this ) ) ;
32+ Hooks . on ( 'youtubeDJ.queueClear' , this . onQueueClear . bind ( this ) ) ;
33+ }
34+
35+ /**
36+ * Check if user can add videos to queue
37+ */
38+ private canAddToQueue ( ) : boolean {
39+ // Check if Group Mode is enabled
40+ const groupMode = game . settings . get ( 'bardic-inspiration' , 'youtubeDJ.groupMode' ) as boolean ;
41+
42+ if ( groupMode ) {
43+ // In Group Mode, any user in the session can add videos
44+ const sessionState = this . store . getSessionState ( ) ;
45+ const currentUserId = game . user ?. id ;
46+ return sessionState . hasJoinedSession &&
47+ sessionState . members . some ( m => m . userId === currentUserId && m . isActive ) ;
48+ } else {
49+ // In single-DJ mode, only the DJ can add videos
50+ return this . store . isDJ ( ) ;
51+ }
3252 }
3353
3454 /**
3555 * Add video to queue
3656 */
3757 async addVideo ( videoInfo : VideoInfo , playNow : boolean = false ) : Promise < void > {
38- if ( ! this . store . isDJ ( ) ) {
39- throw new Error ( 'Only DJ can add videos to queue' ) ;
58+ if ( ! this . canAddToQueue ( ) ) {
59+ const groupMode = game . settings . get ( 'bardic-inspiration' , 'youtubeDJ.groupMode' ) as boolean ;
60+ throw new Error ( groupMode
61+ ? 'You must be in the listening session to add videos to the queue'
62+ : 'Only the DJ can add videos to the queue' ) ;
4063 }
4164
4265 const userId = game . user ?. id ;
@@ -471,7 +494,7 @@ export class QueueManager {
471494 */
472495 async clearQueue ( ) : Promise < void > {
473496 if ( ! this . store . isDJ ( ) ) {
474- throw new Error ( 'Only DJ can clear queue' ) ;
497+ throw new Error ( 'Only the DJ can clear the queue' ) ;
475498 }
476499
477500 logger . debug ( '🎵 YouTube DJ | Clearing queue...' ) ;
@@ -482,6 +505,10 @@ export class QueueManager {
482505 currentIndex : - 1 ,
483506 mode : 'single-dj' ,
484507 djUserId : this . store . getSessionState ( ) . djUserId
508+ } ,
509+ player : {
510+ ...this . store . getPlayerState ( ) ,
511+ playbackState : 'paused'
485512 }
486513 } ) ;
487514
@@ -626,35 +653,47 @@ export class QueueManager {
626653 /**
627654 * Handle queue next event from DJ (for listeners)
628655 */
629- private onQueueNext ( data : { nextIndex : number ; videoItem : any ; timestamp : number } ) : void {
630- // Only update state if we're not the DJ (DJ already updated their state )
631- if ( this . store . isDJ ( ) ) {
656+ private onQueueNext ( data : { nextIndex : number ; videoItem : any ; timestamp : number ; userId : string ; cycledItem ?: any ; isCycling ?: boolean } ) : void {
657+ // Don't sync our own changes (avoid double-processing )
658+ if ( data . userId === game . user ?. id ) {
632659 return ;
633660 }
634661
635662 logger . debug ( '🎵 YouTube DJ | Syncing queue next from DJ:' , data . nextIndex ) ;
636663
637664 const currentQueue = this . store . getQueueState ( ) ;
665+ let newQueue = [ ...currentQueue . items ] ;
666+
667+ // If this is a cycling operation, reorder the queue to match DJ
668+ if ( data . isCycling && data . cycledItem && currentQueue . currentIndex >= 0 ) {
669+ // Remove the current item and add it to the end (same as DJ did)
670+ const cycledItemIndex = currentQueue . currentIndex ;
671+ if ( cycledItemIndex < newQueue . length ) {
672+ const removedItem = newQueue . splice ( cycledItemIndex , 1 ) [ 0 ] ;
673+ newQueue . push ( removedItem ) ;
674+ }
675+ }
638676
639- // Update queue index to match DJ
677+ // Update queue to match DJ's state
640678 this . store . updateState ( {
641679 queue : {
642680 ...currentQueue ,
681+ items : newQueue ,
643682 currentIndex : data . nextIndex
644683 }
645684 } ) ;
646685 }
647686
648687 /**
649- * Handle queue add event from DJ (for listeners)
688+ * Handle queue add event from other users
650689 */
651- private onQueueAdd ( data : { queueItem : any ; playNow : boolean ; timestamp : number } ) : void {
652- // Only update state if we're not the DJ (DJ already updated their state )
653- if ( this . store . isDJ ( ) ) {
690+ private onQueueAdd ( data : { queueItem : any ; playNow : boolean ; timestamp : number ; userId : string } ) : void {
691+ // Don't sync our own changes (avoid double-adding )
692+ if ( data . userId === game . user ?. id ) {
654693 return ;
655694 }
656695
657- logger . debug ( '🎵 YouTube DJ | Syncing queue add from DJ: ' , data . queueItem ?. title ) ;
696+ logger . debug ( '🎵 YouTube DJ | Syncing queue add from user:' , data . userId , '- ', data . queueItem ?. title ) ;
658697
659698 const currentQueue = this . store . getQueueState ( ) ;
660699 const newQueue = [ ...currentQueue . items , data . queueItem ] ;
@@ -757,6 +796,32 @@ export class QueueManager {
757796 } ) ;
758797 }
759798
799+ /**
800+ * Handle queue clear event from DJ (for listeners)
801+ */
802+ private onQueueClear ( data : { timestamp : number ; userId : string } ) : void {
803+ // Don't sync our own changes (avoid double-processing)
804+ if ( data . userId === game . user ?. id ) {
805+ return ;
806+ }
807+
808+ logger . debug ( '🎵 YouTube DJ | Syncing queue clear from DJ' ) ;
809+
810+ // Clear the queue
811+ this . store . updateState ( {
812+ queue : {
813+ items : [ ] ,
814+ currentIndex : - 1 ,
815+ mode : 'single-dj' ,
816+ djUserId : this . store . getSessionState ( ) . djUserId
817+ } ,
818+ player : {
819+ ...this . store . getPlayerState ( ) ,
820+ playbackState : 'paused'
821+ }
822+ } ) ;
823+ }
824+
760825 /**
761826 * Handle video ended event
762827 */
@@ -823,6 +888,7 @@ export class QueueManager {
823888 Hooks . off ( 'youtubeDJ.queueAdd' , this . onQueueAdd . bind ( this ) ) ;
824889 Hooks . off ( 'youtubeDJ.queueRemove' , this . onQueueRemove . bind ( this ) ) ;
825890 Hooks . off ( 'youtubeDJ.queueUpdate' , this . onQueueUpdate . bind ( this ) ) ;
891+ Hooks . off ( 'youtubeDJ.queueClear' , this . onQueueClear . bind ( this ) ) ;
826892 logger . debug ( '🎵 YouTube DJ | QueueManager destroyed' ) ;
827893 }
828894}
0 commit comments