diff --git a/server/controllers/MeController.js b/server/controllers/MeController.js index b5147fb7..d14c07e3 100644 --- a/server/controllers/MeController.js +++ b/server/controllers/MeController.js @@ -33,6 +33,39 @@ class MeController { res.json(payload) } + // GET: api/me/item/listening-sessions/:libraryItemId/:episodeId + async getListeningSessions(req, res) { + const libraryItem = await Database.libraryItemModel.getOldById(req.params.libraryItemId) + const episode = (req.params.episodeId && libraryItem && libraryItem.isPodcast) ? libraryItem.media.getEpisode(req.params.episodeId) : null + + if (!libraryItem || (libraryItem.isPodcast && !episode)) { + Logger.error(`[PlaybackSessionManager] listening-sessions: Media item not found for library item id "${req.params.id}"`) + return { + success: false, + error: 'Media item not found' + } + } + + const mediaItemId = episode ? episode.id : libraryItem.media.id + let listeningSessions = await this.getUserItemListeningSessionsHelper(req.user.id, mediaItemId) + + const itemsPerPage = toNumber(req.query.itemsPerPage, 10) || 10 + const page = toNumber(req.query.page, 0) + + const start = page * itemsPerPage + const sessions = listeningSessions.slice(start, start + itemsPerPage) + + const payload = { + total: listeningSessions.length, + numPages: Math.ceil(listeningSessions.length / itemsPerPage), + page, + itemsPerPage, + sessions + } + + res.json(payload) + } + // GET: api/me/listening-stats async getListeningStats(req, res) { const listeningStats = await this.getUserListeningStatsHelpers(req.user.id) @@ -337,9 +370,9 @@ class MeController { /** * GET: /api/me/stats/year/:year - * - * @param {import('express').Request} req - * @param {import('express').Response} res + * + * @param {import('express').Request} req + * @param {import('express').Response} res */ async getStatsForYear(req, res) { const year = Number(req.params.year) @@ -351,4 +384,4 @@ class MeController { res.json(data) } } -module.exports = new MeController() \ No newline at end of file +module.exports = new MeController() diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 43e7c907..fc5d6a29 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -166,6 +166,8 @@ class ApiRouter { // this.router.get('/me', MeController.getCurrentUser.bind(this)) this.router.get('/me/listening-sessions', MeController.getListeningSessions.bind(this)) + this.router.get('/me/item/listening-sessions/:libraryItemId', MeController.getListeningSessions.bind(this)) + this.router.get('/me/item/listening-sessions/:libraryItemId/:episodeId', MeController.getListeningSessions.bind(this)) this.router.get('/me/listening-stats', MeController.getListeningStats.bind(this)) this.router.get('/me/progress/:id/remove-from-continue-listening', MeController.removeItemFromContinueListening.bind(this)) this.router.get('/me/progress/:id/:episodeId?', MeController.getMediaProgress.bind(this)) @@ -425,9 +427,9 @@ class ApiRouter { /** * Used when a series is removed from a book * Series is removed if it only has 1 book - * + * * @param {string} bookId - * @param {string[]} seriesIds + * @param {string[]} seriesIds */ async checkRemoveEmptySeries(bookId, seriesIds) { if (!seriesIds?.length) return @@ -455,7 +457,7 @@ class ApiRouter { /** * Remove an empty series & close an open RSS feed - * @param {import('../models/Series')} series + * @param {import('../models/Series')} series */ async removeEmptySeries(series) { await this.rssFeedManager.closeFeedForEntityId(series.id) @@ -474,6 +476,11 @@ class ApiRouter { return userSessions.sort((a, b) => b.updatedAt - a.updatedAt) } + async getUserItemListeningSessionsHelper(userId, mediaItemId) { + const userSessions = await Database.getPlaybackSessions({ userId, mediaItemId }) + return userSessions.sort((a, b) => b.updatedAt - a.updatedAt) + } + async getUserListeningStatsHelpers(userId) { const today = date.format(new Date(), 'YYYY-MM-DD')