@@ -411,6 +411,31 @@ const routes = {
411411 } ,
412412 } ,
413413 } ) ,
414+ nextSongInfo : createRoute ( {
415+ method : 'get' ,
416+ path : `/api/${ API_VERSION } /queue/next` ,
417+ summary : 'get next song info' ,
418+ description : 'Get information about the next song in the queue (relative index +1)' ,
419+ responses : {
420+ 200 : {
421+ description : 'Success' ,
422+ content : {
423+ 'application/json' : {
424+ schema : z . object ( {
425+ title : z . string ( ) . optional ( ) ,
426+ videoId : z . string ( ) . optional ( ) ,
427+ thumbnail : z . any ( ) . optional ( ) ,
428+ lengthText : z . any ( ) . optional ( ) ,
429+ shortBylineText : z . any ( ) . optional ( ) ,
430+ } ) ,
431+ } ,
432+ } ,
433+ } ,
434+ 204 : {
435+ description : 'No next song in queue' ,
436+ } ,
437+ } ,
438+ } ) ,
414439 queueInfo : createRoute ( {
415440 method : 'get' ,
416441 path : `/api/${ API_VERSION } /queue` ,
@@ -748,6 +773,63 @@ export const register = (
748773 app . openapi ( routes . oldQueueInfo , queueInfo ) ;
749774 app . openapi ( routes . queueInfo , queueInfo ) ;
750775
776+ app . openapi ( routes . nextSongInfo , async ( ctx ) => {
777+ const queueResponsePromise = new Promise < QueueResponse > ( ( resolve ) => {
778+ ipcMain . once ( 'peard:get-queue-response' , ( _ , queue : QueueResponse ) => {
779+ return resolve ( queue ) ;
780+ } ) ;
781+
782+ controller . requestQueueInformation ( ) ;
783+ } ) ;
784+
785+ const queue = await queueResponsePromise ;
786+
787+ if ( ! queue ?. items || queue . items . length === 0 ) {
788+ ctx . status ( 204 ) ;
789+ return ctx . body ( null ) ;
790+ }
791+
792+ // Find the currently selected song
793+ const currentIndex = queue . items . findIndex ( ( item ) => {
794+ const renderer =
795+ item . playlistPanelVideoRenderer ||
796+ item . playlistPanelVideoWrapperRenderer ?. primaryRenderer
797+ ?. playlistPanelVideoRenderer ;
798+ return renderer ?. selected === true ;
799+ } ) ;
800+
801+ // Get the next song (currentIndex + 1)
802+ const nextIndex = currentIndex + 1 ;
803+ if ( nextIndex >= queue . items . length ) {
804+ // No next song available
805+ ctx . status ( 204 ) ;
806+ return ctx . body ( null ) ;
807+ }
808+
809+ const nextItem = queue . items [ nextIndex ] ;
810+ const nextRenderer =
811+ nextItem . playlistPanelVideoRenderer ||
812+ nextItem . playlistPanelVideoWrapperRenderer ?. primaryRenderer
813+ ?. playlistPanelVideoRenderer ;
814+
815+ if ( ! nextRenderer ) {
816+ ctx . status ( 204 ) ;
817+ return ctx . body ( null ) ;
818+ }
819+
820+ // Extract relevant information similar to SongInfo format
821+ const nextSongInfo = {
822+ title : nextRenderer . title ?. runs ?. [ 0 ] ?. text ,
823+ videoId : nextRenderer . videoId ,
824+ thumbnail : nextRenderer . thumbnail ,
825+ lengthText : nextRenderer . lengthText ,
826+ shortBylineText : nextRenderer . shortBylineText ,
827+ } ;
828+
829+ ctx . status ( 200 ) ;
830+ return ctx . json ( nextSongInfo ) ;
831+ } ) ;
832+
751833 app . openapi ( routes . addSongToQueue , ( ctx ) => {
752834 const { videoId, insertPosition } = ctx . req . valid ( 'json' ) ;
753835 controller . addSongToQueue ( videoId , insertPosition ) ;
0 commit comments