77 */
88
99const queueUtils = require ( './queue-utils' ) ;
10+ const {
11+ getFirstQueuedTrackNumber,
12+ playFromQueue
13+ } = require ( './sonos-playback' ) ;
1014
1115// ==========================================
1216// DEPENDENCIES (injected via initialize)
@@ -163,9 +167,12 @@ async function add(input, channel, userName) {
163167 let result = null ;
164168 try {
165169 logger . info ( `Attempting to queue: ${ firstCandidate . name } by ${ firstCandidate . artist } (URI: ${ firstCandidate . uri } )` ) ;
166- await sonos . queue ( firstCandidate . uri ) ;
170+ const queueResult = await sonos . queue ( firstCandidate . uri ) ;
167171 logger . info ( 'Successfully queued track: ' + firstCandidate . name ) ;
168- result = firstCandidate ;
172+ result = {
173+ ...firstCandidate ,
174+ queuePosition : getFirstQueuedTrackNumber ( queueResult , 1 )
175+ } ;
169176 } catch ( e ) {
170177 const errorDetails = e . message || String ( e ) ;
171178 const upnpErrorMatch = errorDetails . match ( / e r r o r C o d e [ > ] ( \d + ) [ < ] / ) ;
@@ -212,61 +219,7 @@ async function add(input, channel, userName) {
212219 if ( state === 'stopped' ) {
213220 ( async ( ) => {
214221 try {
215- try {
216- await sonos . stop ( ) ;
217- await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
218- } catch ( stopErr ) {
219- logger . debug ( 'Stop before play (may already be stopped): ' + stopErr . message ) ;
220- }
221-
222- // Verify queue has items before trying to play
223- let queueReady = false ;
224- let retries = 0 ;
225- while ( ! queueReady && retries < 5 ) {
226- try {
227- const q = await sonos . getQueue ( ) ;
228- if ( q && q . items && q . items . length > 0 ) {
229- queueReady = true ;
230- logger . debug ( `Queue verified: ${ q . items . length } items ready` ) ;
231- } else {
232- logger . debug ( `Queue not ready yet (attempt ${ retries + 1 } /5), waiting...` ) ;
233- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
234- retries ++ ;
235- }
236- } catch ( queueErr ) {
237- logger . debug ( `Queue check failed (attempt ${ retries + 1 } /5): ${ queueErr . message } ` ) ;
238- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
239- retries ++ ;
240- }
241- }
242-
243- if ( ! queueReady ) {
244- logger . warn ( 'Queue not ready after 5 attempts, attempting playback anyway' ) ;
245- }
246-
247- // Try to activate queue by seeking to position 1
248- try {
249- logger . debug ( 'Attempting to seek to queue position 1 to activate queue' ) ;
250- await sonos . avTransportService ( ) . Seek ( {
251- InstanceID : 0 ,
252- Unit : 'TRACK_NR' ,
253- Target : '1'
254- } ) ;
255- logger . debug ( 'Successfully sought to track 1, queue should be active' ) ;
256- await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
257- } catch ( seekErr ) {
258- logger . debug ( 'Seek failed, trying next() to activate queue: ' + seekErr . message ) ;
259- try {
260- await sonos . next ( ) ;
261- logger . debug ( 'Used next() to activate queue' ) ;
262- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
263- } catch ( nextErr ) {
264- logger . debug ( 'next() also failed: ' + nextErr . message ) ;
265- }
266- }
267-
268- await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
269- await sonos . play ( ) ;
222+ await playFromQueue ( sonos , logger , { trackNumber : result . queuePosition || 1 } ) ;
270223 logger . info ( 'Started playback from queue' ) ;
271224 } catch ( playErr ) {
272225 logger . warn ( 'Failed to start playback: ' + playErr . message ) ;
@@ -426,19 +379,23 @@ async function queueAlbum(result, albumSearchTerm, channel, userName) {
426379 } )
427380 ) ;
428381
429- await Promise . allSettled ( queuePromises ) ;
382+ const queueResults = await Promise . allSettled ( queuePromises ) ;
383+ result . queuePosition = getFirstQueuedTrackNumber (
384+ queueResults . find ( queueResult => queueResult . status === 'fulfilled' && queueResult . value ) ?. value ,
385+ 1
386+ ) ;
430387 logger . info ( `Added ${ allowedTracks . length } tracks from album (filtered ${ blacklistedTracks . length } )` ) ;
431388 } else {
432- await sonos . queue ( result . uri ) ;
389+ const queueResult = await sonos . queue ( result . uri ) ;
390+ result . queuePosition = getFirstQueuedTrackNumber ( queueResult , 1 ) ;
433391 logger . info ( 'Added album: ' + result . name ) ;
434392 }
435393
436394 if ( isStopped ) {
437- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
438- await sonos . play ( ) ;
395+ await playFromQueue ( sonos , logger , { trackNumber : result . queuePosition || 1 } ) ;
439396 logger . info ( 'Started playback after album add' ) ;
440397 } else if ( state !== 'playing' && state !== 'transitioning' ) {
441- await sonos . play ( ) ;
398+ await playFromQueue ( sonos , logger ) ;
442399 logger . info ( 'Player was not playing, started playback.' ) ;
443400 }
444401 } catch ( err ) {
@@ -529,40 +486,36 @@ async function addplaylist(input, channel, userName) {
529486 }
530487 }
531488
489+ let queuedTrackNumber = null ;
490+
532491 // If we have blacklisted tracks, add individually; otherwise use playlist URI
533492 if ( blacklistedTracks . length > 0 ) {
534493 const allowedTracks = playlistTracks . filter ( track =>
535494 ! isTrackBlacklisted ( track . name , track . artist )
536495 ) ;
537496
538497 for ( const track of allowedTracks ) {
539- await sonos . queue ( track . uri ) ;
498+ const queueResult = await sonos . queue ( track . uri ) ;
499+ queuedTrackNumber = queuedTrackNumber || getFirstQueuedTrackNumber ( queueResult , 1 ) ;
540500 }
541501 logger . info ( `Added ${ allowedTracks . length } tracks from playlist (filtered ${ blacklistedTracks . length } )` ) ;
542502 } else {
543- await sonos . queue ( result . uri ) ;
503+ const queueResult = await sonos . queue ( result . uri ) ;
504+ queuedTrackNumber = getFirstQueuedTrackNumber ( queueResult , 1 ) ;
544505 logger . info ( 'Added playlist: ' + result . name ) ;
545506 }
546507
547508 // Start playback if needed
548509 if ( isStopped ) {
549510 try {
550- try {
551- await sonos . stop ( ) ;
552- await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
553- } catch ( stopErr ) {
554- logger . debug ( 'Stop before play (may already be stopped): ' + stopErr . message ) ;
555- }
556-
557- await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
558- await sonos . play ( ) ;
511+ await playFromQueue ( sonos , logger , { trackNumber : queuedTrackNumber || 1 } ) ;
559512 logger . info ( 'Started playback from queue' ) ;
560513 } catch ( playErr ) {
561514 logger . warn ( 'Failed to start playback: ' + playErr . message ) ;
562515 }
563516 } else if ( state !== 'playing' && state !== 'transitioning' ) {
564517 try {
565- await sonos . play ( ) ;
518+ await playFromQueue ( sonos , logger ) ;
566519 logger . info ( 'Player was not playing, started playback.' ) ;
567520 } catch ( playErr ) {
568521 logger . warn ( 'Failed to auto-play: ' + playErr . message ) ;
@@ -578,23 +531,6 @@ async function addplaylist(input, channel, userName) {
578531
579532 logger . info ( `Sending playlist confirmation message: ${ text } ` ) ;
580533 sendMessage ( text , channel , { trackName : result . name } ) ;
581-
582- // Note: Queueing is already done synchronously above (lines 532-545)
583- // This background task only handles playback if needed
584- ( async ( ) => {
585- try {
586- if ( isStopped ) {
587- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
588- await sonos . play ( ) ;
589- logger . info ( 'Started playback after playlist add' ) ;
590- } else if ( state !== 'playing' && state !== 'transitioning' ) {
591- await sonos . play ( ) ;
592- logger . info ( 'Player was not playing, started playback.' ) ;
593- }
594- } catch ( err ) {
595- logger . error ( 'Error in background playlist queueing: ' + err . message ) ;
596- }
597- } ) ( ) ;
598534 } catch ( err ) {
599535 logger . error ( 'Error adding playlist: ' + err . message ) ;
600536 sendMessage ( '🔎 Couldn\'t find that playlist. Try a Spotify link, or use `searchplaylist <name>` to pick one. 🎵' , channel ) ;
@@ -645,7 +581,7 @@ async function append(input, channel, userName) {
645581 }
646582
647583 // Always add to queue (preserving existing tracks)
648- await sonos . queue ( result . uri ) ;
584+ const queueResult = await sonos . queue ( result . uri ) ;
649585 logger . info ( 'Appended track: ' + result . name ) ;
650586
651587 let msg = '✅ Added *' + result . name + '* by _' + result . artist + '_ to the queue!' ;
@@ -656,8 +592,9 @@ async function append(input, channel, userName) {
656592 logger . info ( 'Current state after append: ' + state ) ;
657593
658594 if ( state !== 'playing' && state !== 'transitioning' ) {
659- await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
660- await sonos . play ( ) ;
595+ await playFromQueue ( sonos , logger , {
596+ trackNumber : state === 'stopped' ? getFirstQueuedTrackNumber ( queueResult , null ) : null
597+ } ) ;
661598 logger . info ( 'Started playback after append.' ) ;
662599 msg += ' Playback started! :notes:' ;
663600 }
0 commit comments