diff --git a/src/plugins/api-server/backend/routes/control.ts b/src/plugins/api-server/backend/routes/control.ts index bd8cf78447..8c1d2db450 100644 --- a/src/plugins/api-server/backend/routes/control.ts +++ b/src/plugins/api-server/backend/routes/control.ts @@ -411,6 +411,26 @@ const routes = { }, }, }), + nextSongInfo: createRoute({ + method: 'get', + path: `/api/${API_VERSION}/queue/next`, + summary: 'get next song info', + description: + 'Get information about the next song in the queue (relative index +1)', + responses: { + 200: { + description: 'Success', + content: { + 'application/json': { + schema: SongInfoSchema, + }, + }, + }, + 204: { + description: 'No next song in queue', + }, + }, + }), queueInfo: createRoute({ method: 'get', path: `/api/${API_VERSION}/queue`, @@ -748,6 +768,63 @@ export const register = ( app.openapi(routes.oldQueueInfo, queueInfo); app.openapi(routes.queueInfo, queueInfo); + app.openapi(routes.nextSongInfo, async (ctx) => { + const queueResponsePromise = new Promise((resolve) => { + ipcMain.once('peard:get-queue-response', (_, queue: QueueResponse) => { + return resolve(queue); + }); + + controller.requestQueueInformation(); + }); + + const queue = await queueResponsePromise; + + if (!queue?.items || queue.items.length === 0) { + ctx.status(204); + return ctx.body(null); + } + + // Find the currently selected song + const currentIndex = queue.items.findIndex((item) => { + const renderer = + item.playlistPanelVideoRenderer || + item.playlistPanelVideoWrapperRenderer?.primaryRenderer + ?.playlistPanelVideoRenderer; + return renderer?.selected === true; + }); + + // Get the next song (currentIndex + 1) + const nextIndex = currentIndex + 1; + if (nextIndex >= queue.items.length) { + // No next song available + ctx.status(204); + return ctx.body(null); + } + + const nextItem = queue.items[nextIndex]; + const nextRenderer = + nextItem.playlistPanelVideoRenderer || + nextItem.playlistPanelVideoWrapperRenderer?.primaryRenderer + ?.playlistPanelVideoRenderer; + + if (!nextRenderer) { + ctx.status(204); + return ctx.body(null); + } + + // Extract relevant information similar to SongInfo format + const nextSongInfo = { + title: nextRenderer.title?.runs?.[0]?.text, + videoId: nextRenderer.videoId, + thumbnail: nextRenderer.thumbnail, + lengthText: nextRenderer.lengthText, + shortBylineText: nextRenderer.shortBylineText, + }; + + ctx.status(200); + return ctx.json(nextSongInfo); + }); + app.openapi(routes.addSongToQueue, (ctx) => { const { videoId, insertPosition } = ctx.req.valid('json'); controller.addSongToQueue(videoId, insertPosition);