From fc8c5fa233d3f5a02c8d60506582c2409de6b881 Mon Sep 17 00:00:00 2001 From: Zlendy Date: Sat, 19 Apr 2025 19:56:28 +0200 Subject: [PATCH] feat: API endpoint `/stats/getViewsByLibraryType` --- backend/routes/stats.js | 29 +++++++++++++++++++++++++ backend/swagger.json | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/backend/routes/stats.js b/backend/routes/stats.js index 779ced6..229b657 100644 --- a/backend/routes/stats.js +++ b/backend/routes/stats.js @@ -516,6 +516,35 @@ router.get("/getViewsByHour", async (req, res) => { } }); +router.get("/getViewsByLibraryType", async (req, res) => { + try { + const { days = 30 } = req.query; + + const { rows } = await db.query(` + SELECT COALESCE(i."Type", 'Other') AS type, COUNT(a."NowPlayingItemId") AS count + FROM jf_playback_activity a LEFT JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId" + WHERE a."ActivityDateInserted" BETWEEN NOW() - CAST($1 || ' days' as INTERVAL) AND NOW() + GROUP BY i."Type" + `, [days]); + + const supportedTypes = new Set(["Audio", "Movie", "Series", "Other"]); + const reorganizedData = {}; + + rows.forEach((item) => { + const { type, count } = item; + + if (!supportedTypes.has(type)) return; + reorganizedData[type] = count; + }); + + res.send(reorganizedData); + } catch (error) { + console.log(error); + res.status(503); + res.send(error); + } +}); + router.get("/getGenreUserStats", async (req, res) => { try { const { size = 50, page = 1, userid } = req.query; diff --git a/backend/swagger.json b/backend/swagger.json index 4fc931e..00fc18b 100644 --- a/backend/swagger.json +++ b/backend/swagger.json @@ -3644,6 +3644,53 @@ } } }, + "/stats/getViewsByLibraryType": { + "get": { + "tags": [ + "Stats" + ], + "description": "", + "parameters": [ + { + "name": "authorization", + "in": "header", + "type": "string" + }, + { + "name": "x-api-token", + "in": "header", + "type": "string" + }, + { + "name": "req", + "in": "query", + "type": "string" + }, + { + "name": "days", + "in": "query", + "type": "string" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + }, + "503": { + "description": "Service Unavailable" + } + } + } + }, "/stats/getGenreUserStats": { "get": { "tags": [