From 89f64736f432aa0f25e668b0521c1eae02cca9b8 Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 24 Aug 2024 21:46:23 +0200 Subject: [PATCH 01/18] added libraries/stats endpoint --- server/controllers/LibraryController.js | 63 ++++++++++++------------- server/routers/ApiRouter.js | 1 + server/utils/libraryHelpers.js | 46 ++++++++++++++++++ 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js index 13b82ad402..69b13ab76e 100644 --- a/server/controllers/LibraryController.js +++ b/server/controllers/LibraryController.js @@ -32,6 +32,32 @@ const authorFilters = require('../utils/queries/authorFilters') class LibraryController { constructor() {} + /** + * GET: /api/libraries/stats + * Get stats for all libraries and respond with JSON + * @param {import('express').Request} req + * @param {import('express').Response} res + */ + async allStats(req, res) { + try { + const allLibrariesIds = await Database.libraryModel.getAllLibraryIds(); + const allStats = []; + + for (let i = 0; i < allLibrariesIds.length; i++) { + req.library = { + id: allLibrariesIds[i], + isBook: await Database.libraryModel.getOldById(allLibrariesIds[i]), + }; + const libraryStats = await libraryHelpers.getLibraryStats(req); + allStats.push({ libraryId: req.library.id, stats: libraryStats }); + } + + res.json(allStats); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } + /** * POST: /api/libraries * Create a new library @@ -718,39 +744,12 @@ class LibraryController { * @param {Response} res */ async stats(req, res) { - const stats = { - largestItems: await libraryItemFilters.getLargestItems(req.library.id, 10) - } - - if (req.library.mediaType === 'book') { - const authors = await authorFilters.getAuthorsWithCount(req.library.id, 10) - const genres = await libraryItemsBookFilters.getGenresWithCount(req.library.id) - const bookStats = await libraryItemsBookFilters.getBookLibraryStats(req.library.id) - const longestBooks = await libraryItemsBookFilters.getLongestBooks(req.library.id, 10) - - stats.totalAuthors = await authorFilters.getAuthorsTotalCount(req.library.id) - stats.authorsWithCount = authors - stats.totalGenres = genres.length - stats.genresWithCount = genres - stats.totalItems = bookStats.totalItems - stats.longestItems = longestBooks - stats.totalSize = bookStats.totalSize - stats.totalDuration = bookStats.totalDuration - stats.numAudioTracks = bookStats.numAudioFiles - } else { - const genres = await libraryItemsPodcastFilters.getGenresWithCount(req.library.id) - const podcastStats = await libraryItemsPodcastFilters.getPodcastLibraryStats(req.library.id) - const longestPodcasts = await libraryItemsPodcastFilters.getLongestPodcasts(req.library.id, 10) - - stats.totalGenres = genres.length - stats.genresWithCount = genres - stats.totalItems = podcastStats.totalItems - stats.longestItems = longestPodcasts - stats.totalSize = podcastStats.totalSize - stats.totalDuration = podcastStats.totalDuration - stats.numAudioTracks = podcastStats.numAudioFiles + try { + const stats = await libraryHelpers.getLibraryStats(req); + res.json(stats); + } catch (error) { + res.status(500).json({ error: error.message }); } - res.json(stats) } /** diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 54cd97c094..4e499c61e4 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -72,6 +72,7 @@ class ApiRouter { this.router.get(/^\/libraries/, this.apiCacheManager.middleware) this.router.post('/libraries', LibraryController.create.bind(this)) this.router.get('/libraries', LibraryController.findAll.bind(this)) + this.router.get('/libraries/stats', LibraryController.allStats.bind(this)) this.router.get('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.findOne.bind(this)) this.router.patch('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.update.bind(this)) this.router.delete('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.delete.bind(this)) diff --git a/server/utils/libraryHelpers.js b/server/utils/libraryHelpers.js index ad71ee3fad..65dcf1aa74 100644 --- a/server/utils/libraryHelpers.js +++ b/server/utils/libraryHelpers.js @@ -1,6 +1,10 @@ const { createNewSortInstance } = require('../libs/fastSort') const Database = require('../Database') const { getTitlePrefixAtEnd, isNullOrNaN, getTitleIgnorePrefix } = require('../utils/index') +const { getLargestItems } = require('./queries/libraryItemFilters') +const { getAuthorsWithCount, getAuthorsTotalCount } = require('./queries/authorFilters') +const { getGenresWithCount, getBookLibraryStats, getLongestBooks } = require('./queries/libraryItemsBookFilters') +const { getPodcastLibraryStats, getLongestPodcasts } = require('./queries/libraryItemsPodcastFilters') const naturalSort = createNewSortInstance({ comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare }) @@ -78,6 +82,48 @@ module.exports = { return filteredLibraryItems }, + /** + * Helper method to get stats for a specific library + * @param {import('express').Request} req + * @returns {Promise} stats + */ + async getLibraryStats(req) { + const stats = { + largestItems: await getLargestItems(req.library.id, 10), + }; + + if (req.library.isBook) { + const authors = await getAuthorsWithCount(req.library.id, 10); + const genres = getGenresWithCount(req.library.id); + const bookStats = await getBookLibraryStats(req.library.id); + const longestBooks = await getLongestBooks(req.library.id, 10); + + stats.totalAuthors = await getAuthorsTotalCount(req.library.id); + stats.authorsWithCount = authors; + stats.totalGenres = genres.length; + stats.genresWithCount = genres; + stats.totalItems = bookStats.totalItems; + stats.longestItems = longestBooks; + stats.totalSize = bookStats.totalSize; + stats.totalDuration = bookStats.totalDuration; + stats.numAudioTracks = bookStats.numAudioFiles; + } else { + const genres = getGenresWithCount(req.library.id); + const podcastStats = await getPodcastLibraryStats(req.library.id); + const longestPodcasts = await getLongestPodcasts(req.library.id, 10); + + stats.totalGenres = genres.length; + stats.genresWithCount = genres; + stats.totalItems = podcastStats.totalItems; + stats.longestItems = longestPodcasts; + stats.totalSize = podcastStats.totalSize; + stats.totalDuration = podcastStats.totalDuration; + stats.numAudioTracks = podcastStats.numAudioFiles; + } + + return stats; + }, + /** * * @param {*} payload From 858ea5010a1f2743dcfeb448c9fa7ad9e1b00821 Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 24 Aug 2024 21:55:13 +0200 Subject: [PATCH 02/18] fixed wrong ide completions --- server/controllers/LibraryController.js | 2 +- server/utils/libraryHelpers.js | 28 ++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js index 69b13ab76e..77ebbc5cbf 100644 --- a/server/controllers/LibraryController.js +++ b/server/controllers/LibraryController.js @@ -46,7 +46,7 @@ class LibraryController { for (let i = 0; i < allLibrariesIds.length; i++) { req.library = { id: allLibrariesIds[i], - isBook: await Database.libraryModel.getOldById(allLibrariesIds[i]), + mediaType: (await Database.libraryModel.getOldById(allLibrariesIds[i])).mediaType, }; const libraryStats = await libraryHelpers.getLibraryStats(req); allStats.push({ libraryId: req.library.id, stats: libraryStats }); diff --git a/server/utils/libraryHelpers.js b/server/utils/libraryHelpers.js index 65dcf1aa74..af03ad9391 100644 --- a/server/utils/libraryHelpers.js +++ b/server/utils/libraryHelpers.js @@ -1,10 +1,10 @@ const { createNewSortInstance } = require('../libs/fastSort') const Database = require('../Database') const { getTitlePrefixAtEnd, isNullOrNaN, getTitleIgnorePrefix } = require('../utils/index') -const { getLargestItems } = require('./queries/libraryItemFilters') -const { getAuthorsWithCount, getAuthorsTotalCount } = require('./queries/authorFilters') -const { getGenresWithCount, getBookLibraryStats, getLongestBooks } = require('./queries/libraryItemsBookFilters') -const { getPodcastLibraryStats, getLongestPodcasts } = require('./queries/libraryItemsPodcastFilters') +const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters') +const authorFilters = require('../utils/queries/authorFilters') +const libraryItemFilters = require('../utils/queries/libraryItemFilters') +const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters') const naturalSort = createNewSortInstance({ comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare }) @@ -89,16 +89,16 @@ module.exports = { */ async getLibraryStats(req) { const stats = { - largestItems: await getLargestItems(req.library.id, 10), + largestItems: await libraryItemFilters.getLargestItems(req.library.id, 10) }; - if (req.library.isBook) { - const authors = await getAuthorsWithCount(req.library.id, 10); - const genres = getGenresWithCount(req.library.id); - const bookStats = await getBookLibraryStats(req.library.id); - const longestBooks = await getLongestBooks(req.library.id, 10); + if (req.library.mediaType === 'book') { + const authors = await authorFilters.getAuthorsWithCount(req.library.id, 10) + const genres = await libraryItemsBookFilters.getGenresWithCount(req.library.id) + const bookStats = await libraryItemsBookFilters.getBookLibraryStats(req.library.id) + const longestBooks = await libraryItemsBookFilters.getLongestBooks(req.library.id, 10) - stats.totalAuthors = await getAuthorsTotalCount(req.library.id); + stats.totalAuthors = await authorFilters.getAuthorsTotalCount(req.library.id) stats.authorsWithCount = authors; stats.totalGenres = genres.length; stats.genresWithCount = genres; @@ -108,9 +108,9 @@ module.exports = { stats.totalDuration = bookStats.totalDuration; stats.numAudioTracks = bookStats.numAudioFiles; } else { - const genres = getGenresWithCount(req.library.id); - const podcastStats = await getPodcastLibraryStats(req.library.id); - const longestPodcasts = await getLongestPodcasts(req.library.id, 10); + const genres = await libraryItemsPodcastFilters.getGenresWithCount(req.library.id) + const podcastStats = await libraryItemsPodcastFilters.getPodcastLibraryStats(req.library.id) + const longestPodcasts = await libraryItemsPodcastFilters.getLongestPodcasts(req.library.id, 10) stats.totalGenres = genres.length; stats.genresWithCount = genres; From 3d906347c3a00af8bcb3a08bd383c0a7167f920c Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 24 Aug 2024 22:14:38 +0200 Subject: [PATCH 03/18] added library to be returned instead of libraryId and fixed stupid req.library asignment --- server/controllers/LibraryController.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js index 77ebbc5cbf..0336f61568 100644 --- a/server/controllers/LibraryController.js +++ b/server/controllers/LibraryController.js @@ -44,12 +44,10 @@ class LibraryController { const allStats = []; for (let i = 0; i < allLibrariesIds.length; i++) { - req.library = { - id: allLibrariesIds[i], - mediaType: (await Database.libraryModel.getOldById(allLibrariesIds[i])).mediaType, - }; + const library = await Database.libraryModel.getOldById(allLibrariesIds[i]); + req.library = library const libraryStats = await libraryHelpers.getLibraryStats(req); - allStats.push({ libraryId: req.library.id, stats: libraryStats }); + allStats.push({ library: library, stats: libraryStats }); } res.json(allStats); From 0e205b59d84f307fecfe1648a66b197c7c999e27 Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 24 Aug 2024 22:29:19 +0200 Subject: [PATCH 04/18] copy pasted and edited some parts in all-stats --- client/components/app/ConfigSideNav.vue | 5 + client/pages/library/_library/all-stats.vue | 182 ++++++++++++++++++++ client/strings/en-us.json | 1 + 3 files changed, 188 insertions(+) create mode 100644 client/pages/library/_library/all-stats.vue diff --git a/client/components/app/ConfigSideNav.vue b/client/components/app/ConfigSideNav.vue index adc99e5ae5..b961a4453c 100644 --- a/client/components/app/ConfigSideNav.vue +++ b/client/components/app/ConfigSideNav.vue @@ -109,6 +109,11 @@ export default { id: 'config-authentication', title: this.$strings.HeaderAuthentication, path: '/config/authentication' + }, + { + id: 'all-libraries-stats', + title: this.$strings.HeaderAllLibrariesStats, + path: '/libraries/stats' } ] diff --git a/client/pages/library/_library/all-stats.vue b/client/pages/library/_library/all-stats.vue new file mode 100644 index 0000000000..a579cf9c08 --- /dev/null +++ b/client/pages/library/_library/all-stats.vue @@ -0,0 +1,182 @@ + + + diff --git a/client/strings/en-us.json b/client/strings/en-us.json index 7420c1e75a..c048c297b2 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -106,6 +106,7 @@ "ErrorUploadLacksTitle": "Must have a title", "HeaderAccount": "Account", "HeaderAdvanced": "Advanced", + "HeaderAllLibrariesStats": "All Libraries Stats", "HeaderAppriseNotificationSettings": "Apprise Notification Settings", "HeaderAudioTracks": "Audio Tracks", "HeaderAudiobookTools": "Audiobook File Management Tools", From cbd042dd8eeaa2db74061055d6a5ef9f14c7c930 Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:49:51 +0200 Subject: [PATCH 05/18] refactored libraries-stats and changed path --- client/components/app/ConfigSideNav.vue | 2 +- .../libraries-stats.vue} | 78 +++++++++---------- 2 files changed, 38 insertions(+), 42 deletions(-) rename client/pages/{library/_library/all-stats.vue => config/libraries-stats.vue} (76%) diff --git a/client/components/app/ConfigSideNav.vue b/client/components/app/ConfigSideNav.vue index b961a4453c..4ace509758 100644 --- a/client/components/app/ConfigSideNav.vue +++ b/client/components/app/ConfigSideNav.vue @@ -113,7 +113,7 @@ export default { { id: 'all-libraries-stats', title: this.$strings.HeaderAllLibrariesStats, - path: '/libraries/stats' + path: '/config/libraries-stats' } ] diff --git a/client/pages/library/_library/all-stats.vue b/client/pages/config/libraries-stats.vue similarity index 76% rename from client/pages/library/_library/all-stats.vue rename to client/pages/config/libraries-stats.vue index a579cf9c08..fbd415a07e 100644 --- a/client/pages/library/_library/all-stats.vue +++ b/client/pages/config/libraries-stats.vue @@ -1,7 +1,5 @@ -
+

{{ $strings.HeaderStatsTop10Authors }}

{{ $strings.MessageNoAuthors }}

diff --git a/client/pages/library/_library/stats.vue b/client/pages/library/_library/stats.vue index ae72c2e896..46d2a4666d 100644 --- a/client/pages/library/_library/stats.vue +++ b/client/pages/library/_library/stats.vue @@ -1,6 +1,8 @@
-
+

{{ $strings.HeaderStatsTop10Authors }}

{{ $strings.MessageNoAuthors }}

+ +