@@ -115,6 +115,15 @@ export class SavedQueuesManager {
115115 // Save to world settings
116116 await game . settings . set ( 'core' , 'youtubeDJ.savedQueues' , updatedQueues ) ;
117117
118+ // Update queue state to track this as the currently loaded queue
119+ this . store . updateState ( {
120+ queue : {
121+ ...currentQueue ,
122+ currentlyLoadedQueueId : savedQueue . id ,
123+ isModifiedFromSaved : false
124+ }
125+ } ) ;
126+
118127 // Broadcast save event
119128 this . broadcastMessage ( {
120129 type : 'QUEUE_SAVED' ,
@@ -160,12 +169,15 @@ export class SavedQueuesManager {
160169 newItems = [ ...currentQueue . items , ...savedQueue . items ] ;
161170 }
162171
163- // Update queue state
172+ // Update queue state with tracking
164173 this . store . updateState ( {
165174 queue : {
166175 ...currentQueue ,
167176 items : newItems ,
168- currentIndex : replace && newItems . length > 0 ? 0 : currentQueue . currentIndex
177+ currentIndex : replace && newItems . length > 0 ? 0 : currentQueue . currentIndex ,
178+ // Track the loaded queue only if we replaced (not if we appended)
179+ currentlyLoadedQueueId : replace ? queueId : null ,
180+ isModifiedFromSaved : false
169181 }
170182 } ) ;
171183
@@ -324,6 +336,134 @@ export class SavedQueuesManager {
324336 ui . notifications ?. success ( `Queue renamed to "${ trimmedName } "` ) ;
325337 }
326338
339+ /**
340+ * Save changes to the currently loaded saved queue
341+ */
342+ async saveChangesToCurrentQueue ( ) : Promise < SavedQueue | null > {
343+ if ( ! this . store . isDJ ( ) ) {
344+ throw new Error ( 'Only the DJ can save queue changes' ) ;
345+ }
346+
347+ const currentQueue = this . store . getQueueState ( ) ;
348+
349+ // Check if there's a currently loaded saved queue
350+ if ( ! currentQueue . currentlyLoadedQueueId ) {
351+ throw new Error ( 'No saved queue is currently loaded. Use "Save Queue" to create a new saved queue.' ) ;
352+ }
353+
354+ // Check if the queue has been modified
355+ if ( ! currentQueue . isModifiedFromSaved ) {
356+ ui . notifications ?. info ( 'No changes to save - queue is already up to date' ) ;
357+ return null ;
358+ }
359+
360+ const savedQueue = this . getSavedQueue ( currentQueue . currentlyLoadedQueueId ) ;
361+ if ( ! savedQueue ) {
362+ throw new Error ( 'Currently loaded saved queue not found' ) ;
363+ }
364+
365+ if ( currentQueue . items . length === 0 ) {
366+ throw new Error ( 'Cannot save an empty queue' ) ;
367+ }
368+
369+ logger . debug ( '🎵 YouTube DJ | Saving changes to currently loaded queue:' , savedQueue . name ) ;
370+
371+ // Create updated saved queue
372+ const updatedQueue : SavedQueue = {
373+ ...savedQueue ,
374+ items : [ ...currentQueue . items ] , // Deep copy current items
375+ updatedAt : Date . now ( )
376+ } ;
377+
378+ // Update saved queues list
379+ const savedQueues = this . getSavedQueues ( ) ;
380+ const updatedQueues = savedQueues . map ( q =>
381+ q . id === currentQueue . currentlyLoadedQueueId ? updatedQueue : q
382+ ) ;
383+
384+ // Save to world settings
385+ await game . settings . set ( 'core' , 'youtubeDJ.savedQueues' , updatedQueues ) ;
386+
387+ // Update queue state to reflect saved changes
388+ this . store . updateState ( {
389+ queue : {
390+ ...currentQueue ,
391+ isModifiedFromSaved : false
392+ }
393+ } ) ;
394+
395+ // Broadcast save event
396+ this . broadcastMessage ( {
397+ type : 'QUEUE_SAVED' ,
398+ userId : game . user ?. id || '' ,
399+ timestamp : Date . now ( ) ,
400+ data : {
401+ savedQueue : updatedQueue ,
402+ isOverwrite : true ,
403+ isCurrentQueueUpdate : true
404+ }
405+ } ) ;
406+
407+ logger . info ( '🎵 YouTube DJ | Changes saved to queue:' , savedQueue . name ) ;
408+ ui . notifications ?. success ( `Changes saved to "${ savedQueue . name } "` ) ;
409+
410+ return updatedQueue ;
411+ }
412+
413+ /**
414+ * Get information about the currently loaded saved queue
415+ */
416+ getCurrentlyLoadedQueue ( ) : { savedQueue : SavedQueue | null ; hasChanges : boolean } {
417+ const currentQueue = this . store . getQueueState ( ) ;
418+
419+ if ( ! currentQueue . currentlyLoadedQueueId ) {
420+ return { savedQueue : null , hasChanges : false } ;
421+ }
422+
423+ const savedQueue = this . getSavedQueue ( currentQueue . currentlyLoadedQueueId ) ;
424+ return {
425+ savedQueue,
426+ hasChanges : currentQueue . isModifiedFromSaved
427+ } ;
428+ }
429+
430+ /**
431+ * Mark the current queue as modified from the saved version
432+ */
433+ markQueueAsModified ( ) : void {
434+ const currentQueue = this . store . getQueueState ( ) ;
435+
436+ if ( currentQueue . currentlyLoadedQueueId && ! currentQueue . isModifiedFromSaved ) {
437+ this . store . updateState ( {
438+ queue : {
439+ ...currentQueue ,
440+ isModifiedFromSaved : true
441+ }
442+ } ) ;
443+
444+ logger . debug ( '🎵 YouTube DJ | Queue marked as modified from saved version' ) ;
445+ }
446+ }
447+
448+ /**
449+ * Clear the currently loaded queue tracking (when creating a new queue from scratch)
450+ */
451+ clearCurrentlyLoadedQueue ( ) : void {
452+ const currentQueue = this . store . getQueueState ( ) ;
453+
454+ if ( currentQueue . currentlyLoadedQueueId || currentQueue . isModifiedFromSaved ) {
455+ this . store . updateState ( {
456+ queue : {
457+ ...currentQueue ,
458+ currentlyLoadedQueueId : null ,
459+ isModifiedFromSaved : false
460+ }
461+ } ) ;
462+
463+ logger . debug ( '🎵 YouTube DJ | Cleared currently loaded queue tracking' ) ;
464+ }
465+ }
466+
327467 /**
328468 * Export a saved queue to JSON
329469 */
0 commit comments