2021-08-18 00:01:11 +02:00
const express = require ( 'express' )
2021-09-22 03:57:33 +02:00
const Path = require ( 'path' )
2022-11-24 22:53:58 +01:00
const Logger = require ( '../Logger' )
const SocketAuthority = require ( '../SocketAuthority' )
2022-07-06 02:53:01 +02:00
const fs = require ( '../libs/fsExtra' )
2022-07-07 02:18:27 +02:00
const date = require ( '../libs/dateAndTime' )
2022-03-18 01:10:47 +01:00
const LibraryController = require ( '../controllers/LibraryController' )
const UserController = require ( '../controllers/UserController' )
const CollectionController = require ( '../controllers/CollectionController' )
2022-11-26 22:14:45 +01:00
const PlaylistController = require ( '../controllers/PlaylistController' )
2022-03-18 01:10:47 +01:00
const MeController = require ( '../controllers/MeController' )
const BackupController = require ( '../controllers/BackupController' )
const LibraryItemController = require ( '../controllers/LibraryItemController' )
const SeriesController = require ( '../controllers/SeriesController' )
2022-11-19 20:28:06 +01:00
const FileSystemController = require ( '../controllers/FileSystemController' )
2022-03-18 01:10:47 +01:00
const AuthorController = require ( '../controllers/AuthorController' )
const SessionController = require ( '../controllers/SessionController' )
2022-03-19 16:13:10 +01:00
const PodcastController = require ( '../controllers/PodcastController' )
2022-09-22 01:01:10 +02:00
const NotificationController = require ( '../controllers/NotificationController' )
2023-05-30 00:38:38 +02:00
const EmailController = require ( '../controllers/EmailController' )
2022-11-19 20:28:06 +01:00
const SearchController = require ( '../controllers/SearchController' )
const CacheController = require ( '../controllers/CacheController' )
const ToolsController = require ( '../controllers/ToolsController' )
2022-12-26 23:58:36 +01:00
const RSSFeedController = require ( '../controllers/RSSFeedController' )
2022-03-18 17:51:55 +01:00
const MiscController = require ( '../controllers/MiscController' )
2022-03-18 01:10:47 +01:00
const BookFinder = require ( '../finders/BookFinder' )
const AuthorFinder = require ( '../finders/AuthorFinder' )
const PodcastFinder = require ( '../finders/PodcastFinder' )
2023-01-07 20:05:33 +01:00
const MusicFinder = require ( '../finders/MusicFinder' )
2022-03-18 01:10:47 +01:00
const Author = require ( '../objects/entities/Author' )
const Series = require ( '../objects/entities/Series' )
class ApiRouter {
2022-11-24 22:53:58 +01:00
constructor ( Server ) {
this . db = Server . db
this . auth = Server . auth
this . scanner = Server . scanner
this . playbackSessionManager = Server . playbackSessionManager
this . abMergeManager = Server . abMergeManager
this . backupManager = Server . backupManager
this . coverManager = Server . coverManager
this . watcher = Server . watcher
this . cacheManager = Server . cacheManager
this . podcastManager = Server . podcastManager
this . audioMetadataManager = Server . audioMetadataManager
this . rssFeedManager = Server . rssFeedManager
this . cronManager = Server . cronManager
this . notificationManager = Server . notificationManager
2023-05-30 00:38:38 +02:00
this . emailManager = Server . emailManager
2022-11-24 22:53:58 +01:00
this . taskManager = Server . taskManager
2021-08-18 00:01:11 +02:00
2021-10-28 21:41:42 +02:00
this . bookFinder = new BookFinder ( )
2022-02-27 20:47:52 +01:00
this . authorFinder = new AuthorFinder ( )
2022-03-06 23:32:04 +01:00
this . podcastFinder = new PodcastFinder ( )
2023-01-07 20:05:33 +01:00
this . musicFinder = new MusicFinder ( )
2021-10-28 21:41:42 +02:00
2021-08-18 00:01:11 +02:00
this . router = express ( )
2023-02-01 21:34:01 +01:00
this . router . disable ( 'x-powered-by' )
2021-08-18 00:01:11 +02:00
this . init ( )
}
init ( ) {
2021-11-22 03:00:40 +01:00
//
// Library Routes
//
this . router . post ( '/libraries' , LibraryController . create . bind ( this ) )
this . router . get ( '/libraries' , LibraryController . findAll . bind ( this ) )
2021-12-01 03:02:40 +01:00
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 ) )
2022-03-11 01:45:02 +01:00
this . router . get ( '/libraries/:id/items' , LibraryController . middleware . bind ( this ) , LibraryController . getLibraryItems . bind ( this ) )
2022-04-25 01:25:33 +02:00
this . router . delete ( '/libraries/:id/issues' , LibraryController . middleware . bind ( this ) , LibraryController . removeLibraryItemsWithIssues . bind ( this ) )
2023-03-05 17:35:34 +01:00
this . router . get ( '/libraries/:id/episode-downloads' , LibraryController . middleware . bind ( this ) , LibraryController . getEpisodeDownloadQueue . bind ( this ) )
2021-12-02 02:07:03 +01:00
this . router . get ( '/libraries/:id/series' , LibraryController . middleware . bind ( this ) , LibraryController . getAllSeriesForLibrary . bind ( this ) )
2021-12-01 03:02:40 +01:00
this . router . get ( '/libraries/:id/collections' , LibraryController . middleware . bind ( this ) , LibraryController . getCollectionsForLibrary . bind ( this ) )
2022-11-27 00:24:46 +01:00
this . router . get ( '/libraries/:id/playlists' , LibraryController . middleware . bind ( this ) , LibraryController . getUserPlaylistsForLibrary . bind ( this ) )
2023-01-03 01:02:04 +01:00
this . router . get ( '/libraries/:id/albums' , LibraryController . middleware . bind ( this ) , LibraryController . getAlbumsForLibrary . bind ( this ) )
2022-04-24 23:56:30 +02:00
this . router . get ( '/libraries/:id/personalized' , LibraryController . middleware . bind ( this ) , LibraryController . getLibraryUserPersonalizedOptimal . bind ( this ) )
2022-03-11 01:45:02 +01:00
this . router . get ( '/libraries/:id/filterdata' , LibraryController . middleware . bind ( this ) , LibraryController . getLibraryFilterData . bind ( this ) )
2021-12-01 03:02:40 +01:00
this . router . get ( '/libraries/:id/search' , LibraryController . middleware . bind ( this ) , LibraryController . search . bind ( this ) )
2021-12-02 02:07:03 +01:00
this . router . get ( '/libraries/:id/stats' , LibraryController . middleware . bind ( this ) , LibraryController . stats . bind ( this ) )
2021-12-03 02:02:38 +01:00
this . router . get ( '/libraries/:id/authors' , LibraryController . middleware . bind ( this ) , LibraryController . getAuthors . bind ( this ) )
2023-04-30 21:11:54 +02:00
this . router . get ( '/libraries/:id/narrators' , LibraryController . middleware . bind ( this ) , LibraryController . getNarrators . bind ( this ) )
this . router . patch ( '/libraries/:id/narrators/:narratorId' , LibraryController . middleware . bind ( this ) , LibraryController . updateNarrator . bind ( this ) )
this . router . delete ( '/libraries/:id/narrators/:narratorId' , LibraryController . middleware . bind ( this ) , LibraryController . removeNarrator . bind ( this ) )
2022-07-30 22:52:13 +02:00
this . router . get ( '/libraries/:id/matchall' , LibraryController . middleware . bind ( this ) , LibraryController . matchAll . bind ( this ) )
2023-02-04 00:50:42 +01:00
this . router . post ( '/libraries/:id/scan' , LibraryController . middleware . bind ( this ) , LibraryController . scan . bind ( this ) )
2022-09-16 23:59:16 +02:00
this . router . get ( '/libraries/:id/recent-episodes' , LibraryController . middleware . bind ( this ) , LibraryController . getRecentEpisodes . bind ( this ) )
2023-05-28 22:10:34 +02:00
this . router . get ( '/libraries/:id/opml' , LibraryController . middleware . bind ( this ) , LibraryController . getOPMLFile . bind ( this ) )
2022-03-13 23:10:48 +01:00
this . router . post ( '/libraries/order' , LibraryController . reorder . bind ( this ) )
2022-03-11 01:45:02 +01:00
//
// Item Routes
//
2023-05-27 21:51:03 +02:00
this . router . post ( '/items/batch/delete' , LibraryItemController . batchDelete . bind ( this ) )
this . router . post ( '/items/batch/update' , LibraryItemController . batchUpdate . bind ( this ) )
this . router . post ( '/items/batch/get' , LibraryItemController . batchGet . bind ( this ) )
this . router . post ( '/items/batch/quickmatch' , LibraryItemController . batchQuickMatch . bind ( this ) )
this . router . post ( '/items/batch/scan' , LibraryItemController . batchScan . bind ( this ) )
2022-03-14 01:34:31 +01:00
this . router . delete ( '/items/all' , LibraryItemController . deleteAll . bind ( this ) )
2022-03-11 01:45:02 +01:00
this . router . get ( '/items/:id' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . findOne . bind ( this ) )
2022-03-12 02:46:32 +01:00
this . router . patch ( '/items/:id' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . update . bind ( this ) )
2022-03-13 00:45:32 +01:00
this . router . delete ( '/items/:id' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . delete . bind ( this ) )
2023-04-10 00:05:35 +02:00
this . router . get ( '/items/:id/download' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . download . bind ( this ) )
2022-03-12 02:46:32 +01:00
this . router . patch ( '/items/:id/media' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . updateMedia . bind ( this ) )
2022-03-11 01:45:02 +01:00
this . router . get ( '/items/:id/cover' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . getCover . bind ( this ) )
2022-03-13 00:45:32 +01:00
this . router . post ( '/items/:id/cover' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . uploadCover . bind ( this ) )
this . router . patch ( '/items/:id/cover' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . updateCover . bind ( this ) )
this . router . delete ( '/items/:id/cover' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . removeCover . bind ( this ) )
2022-03-14 01:34:31 +01:00
this . router . post ( '/items/:id/match' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . match . bind ( this ) )
2022-03-18 01:10:47 +01:00
this . router . post ( '/items/:id/play' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . startPlaybackSession . bind ( this ) )
2022-03-26 23:41:26 +01:00
this . router . post ( '/items/:id/play/:episodeId' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . startEpisodePlaybackSession . bind ( this ) )
2022-03-26 17:59:34 +01:00
this . router . patch ( '/items/:id/tracks' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . updateTracks . bind ( this ) )
2023-02-04 00:50:42 +01:00
this . router . post ( '/items/:id/scan' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . scan . bind ( this ) )
2022-09-25 22:56:06 +02:00
this . router . get ( '/items/:id/tone-object' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . getToneMetadataObject . bind ( this ) )
2022-05-11 00:03:41 +02:00
this . router . post ( '/items/:id/chapters' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . updateMediaChapters . bind ( this ) )
2022-10-02 22:24:32 +02:00
this . router . post ( '/items/:id/tone-scan/:index?' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . toneScan . bind ( this ) )
2023-05-28 19:34:22 +02:00
this . router . get ( '/items/:id/file/:fileid' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . getLibraryFile . bind ( this ) )
this . router . delete ( '/items/:id/file/:fileid' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . deleteLibraryFile . bind ( this ) )
this . router . get ( '/items/:id/file/:fileid/download' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . downloadLibraryFile . bind ( this ) )
2023-06-10 19:46:57 +02:00
this . router . get ( '/items/:id/ebook/:fileid?' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . getEBookFile . bind ( this ) )
this . router . patch ( '/items/:id/ebook/:fileid/status' , LibraryItemController . middleware . bind ( this ) , LibraryItemController . updateEbookFileStatus . bind ( this ) )
2022-03-11 01:45:02 +01:00
2021-11-22 03:00:40 +01:00
//
// User Routes
//
2022-09-26 00:11:39 +02:00
this . router . post ( '/users' , UserController . middleware . bind ( this ) , UserController . create . bind ( this ) )
this . router . get ( '/users' , UserController . middleware . bind ( this ) , UserController . findAll . bind ( this ) )
2022-11-11 00:42:20 +01:00
this . router . get ( '/users/online' , UserController . getOnlineUsers . bind ( this ) )
2022-09-26 00:11:39 +02:00
this . router . get ( '/users/:id' , UserController . middleware . bind ( this ) , UserController . findOne . bind ( this ) )
this . router . patch ( '/users/:id' , UserController . middleware . bind ( this ) , UserController . update . bind ( this ) )
this . router . delete ( '/users/:id' , UserController . middleware . bind ( this ) , UserController . delete . bind ( this ) )
2021-11-22 03:00:40 +01:00
2022-09-26 00:11:39 +02:00
this . router . get ( '/users/:id/listening-sessions' , UserController . middleware . bind ( this ) , UserController . getListeningSessions . bind ( this ) )
this . router . get ( '/users/:id/listening-stats' , UserController . middleware . bind ( this ) , UserController . getListeningStats . bind ( this ) )
this . router . post ( '/users/:id/purge-media-progress' , UserController . middleware . bind ( this ) , UserController . purgeMediaProgress . bind ( this ) )
2021-11-22 03:00:40 +01:00
//
// Collection Routes
//
2022-08-31 22:46:10 +02:00
this . router . post ( '/collections' , CollectionController . middleware . bind ( this ) , CollectionController . create . bind ( this ) )
2021-11-22 03:00:40 +01:00
this . router . get ( '/collections' , CollectionController . findAll . bind ( this ) )
2022-08-31 22:46:10 +02:00
this . router . get ( '/collections/:id' , CollectionController . middleware . bind ( this ) , CollectionController . findOne . bind ( this ) )
this . router . patch ( '/collections/:id' , CollectionController . middleware . bind ( this ) , CollectionController . update . bind ( this ) )
this . router . delete ( '/collections/:id' , CollectionController . middleware . bind ( this ) , CollectionController . delete . bind ( this ) )
this . router . post ( '/collections/:id/book' , CollectionController . middleware . bind ( this ) , CollectionController . addBook . bind ( this ) )
this . router . delete ( '/collections/:id/book/:bookId' , CollectionController . middleware . bind ( this ) , CollectionController . removeBook . bind ( this ) )
this . router . post ( '/collections/:id/batch/add' , CollectionController . middleware . bind ( this ) , CollectionController . addBatch . bind ( this ) )
this . router . post ( '/collections/:id/batch/remove' , CollectionController . middleware . bind ( this ) , CollectionController . removeBatch . bind ( this ) )
2021-11-22 03:00:40 +01:00
2022-11-26 22:14:45 +01:00
//
// Playlist Routes
//
2022-12-18 00:31:19 +01:00
this . router . post ( '/playlists' , PlaylistController . create . bind ( this ) )
2022-11-26 22:14:45 +01:00
this . router . get ( '/playlists' , PlaylistController . findAllForUser . bind ( this ) )
this . router . get ( '/playlists/:id' , PlaylistController . middleware . bind ( this ) , PlaylistController . findOne . bind ( this ) )
this . router . patch ( '/playlists/:id' , PlaylistController . middleware . bind ( this ) , PlaylistController . update . bind ( this ) )
this . router . delete ( '/playlists/:id' , PlaylistController . middleware . bind ( this ) , PlaylistController . delete . bind ( this ) )
this . router . post ( '/playlists/:id/item' , PlaylistController . middleware . bind ( this ) , PlaylistController . addItem . bind ( this ) )
this . router . delete ( '/playlists/:id/item/:libraryItemId/:episodeId?' , PlaylistController . middleware . bind ( this ) , PlaylistController . removeItem . bind ( this ) )
this . router . post ( '/playlists/:id/batch/add' , PlaylistController . middleware . bind ( this ) , PlaylistController . addBatch . bind ( this ) )
this . router . post ( '/playlists/:id/batch/remove' , PlaylistController . middleware . bind ( this ) , PlaylistController . removeBatch . bind ( this ) )
2022-12-18 00:31:19 +01:00
this . router . post ( '/playlists/collection/:collectionId' , PlaylistController . createFromCollection . bind ( this ) )
2022-11-26 22:14:45 +01:00
2021-11-22 03:00:40 +01:00
//
// Current User Routes (Me)
//
2023-02-05 23:52:17 +01:00
this . router . get ( '/me' , MeController . getCurrentUser . bind ( this ) )
2021-11-22 03:00:40 +01:00
this . router . get ( '/me/listening-sessions' , MeController . getListeningSessions . bind ( this ) )
this . router . get ( '/me/listening-stats' , MeController . getListeningStats . bind ( this ) )
2022-09-29 00:45:39 +02:00
this . router . get ( '/me/progress/:id/remove-from-continue-listening' , MeController . removeItemFromContinueListening . bind ( this ) )
2022-06-04 01:59:42 +02:00
this . router . get ( '/me/progress/:id/:episodeId?' , MeController . getMediaProgress . bind ( this ) )
2022-04-24 00:17:05 +02:00
this . router . patch ( '/me/progress/batch/update' , MeController . batchUpdateMediaProgress . bind ( this ) )
2022-03-26 17:59:34 +01:00
this . router . patch ( '/me/progress/:id' , MeController . createUpdateMediaProgress . bind ( this ) )
this . router . delete ( '/me/progress/:id' , MeController . removeMediaProgress . bind ( this ) )
2022-03-26 23:41:26 +01:00
this . router . patch ( '/me/progress/:id/:episodeId' , MeController . createUpdateEpisodeMediaProgress . bind ( this ) )
2022-03-18 02:28:04 +01:00
this . router . post ( '/me/item/:id/bookmark' , MeController . createBookmark . bind ( this ) )
this . router . patch ( '/me/item/:id/bookmark' , MeController . updateBookmark . bind ( this ) )
this . router . delete ( '/me/item/:id/bookmark/:time' , MeController . removeBookmark . bind ( this ) )
2021-11-22 03:00:40 +01:00
this . router . patch ( '/me/password' , MeController . updatePassword . bind ( this ) )
2023-02-05 23:52:17 +01:00
this . router . post ( '/me/sync-local-progress' , MeController . syncLocalMediaProgress . bind ( this ) ) // TODO: Deprecated. Removed from Android. Only used in iOS app now.
2022-08-14 17:24:41 +02:00
this . router . get ( '/me/items-in-progress' , MeController . getAllLibraryItemsInProgress . bind ( this ) )
2022-09-29 00:45:39 +02:00
this . router . get ( '/me/series/:id/remove-from-continue-listening' , MeController . removeSeriesFromContinueListening . bind ( this ) )
2022-11-16 00:20:57 +01:00
this . router . get ( '/me/series/:id/readd-to-continue-listening' , MeController . readdSeriesFromContinueListening . bind ( this ) )
2021-11-22 03:00:40 +01:00
//
// Backup Routes
//
2022-11-24 20:14:29 +01:00
this . router . get ( '/backups' , BackupController . middleware . bind ( this ) , BackupController . getAll . bind ( this ) )
this . router . post ( '/backups' , BackupController . middleware . bind ( this ) , BackupController . create . bind ( this ) )
this . router . delete ( '/backups/:id' , BackupController . middleware . bind ( this ) , BackupController . delete . bind ( this ) )
this . router . get ( '/backups/:id/apply' , BackupController . middleware . bind ( this ) , BackupController . apply . bind ( this ) )
this . router . post ( '/backups/upload' , BackupController . middleware . bind ( this ) , BackupController . upload . bind ( this ) )
2021-11-22 03:00:40 +01:00
2021-12-26 18:25:07 +01:00
//
// File System Routes
//
this . router . get ( '/filesystem' , FileSystemController . getPaths . bind ( this ) )
2023-05-27 23:00:34 +02:00
this . router . post ( '/filesystem/pathexists' , FileSystemController . checkPathExists . bind ( this ) )
2021-12-26 18:25:07 +01:00
2021-11-22 03:00:40 +01:00
//
2022-03-12 02:46:32 +01:00
// Author Routes
2021-11-22 03:00:40 +01:00
//
2022-03-13 23:10:48 +01:00
this . router . get ( '/authors/search' , AuthorController . search . bind ( this ) )
2022-03-13 12:42:43 +01:00
this . router . get ( '/authors/:id' , AuthorController . middleware . bind ( this ) , AuthorController . findOne . bind ( this ) )
2022-03-15 00:53:49 +01:00
this . router . patch ( '/authors/:id' , AuthorController . middleware . bind ( this ) , AuthorController . update . bind ( this ) )
2022-03-13 12:42:43 +01:00
this . router . post ( '/authors/:id/match' , AuthorController . middleware . bind ( this ) , AuthorController . match . bind ( this ) )
2022-03-13 16:35:35 +01:00
this . router . get ( '/authors/:id/image' , AuthorController . middleware . bind ( this ) , AuthorController . getImage . bind ( this ) )
2021-11-18 02:19:24 +01:00
2022-03-12 02:46:32 +01:00
//
// Series Routes
//
this . router . get ( '/series/search' , SeriesController . search . bind ( this ) )
2022-03-13 23:10:48 +01:00
this . router . get ( '/series/:id' , SeriesController . middleware . bind ( this ) , SeriesController . findOne . bind ( this ) )
2022-09-28 00:48:45 +02:00
this . router . patch ( '/series/:id' , SeriesController . middleware . bind ( this ) , SeriesController . update . bind ( this ) )
2022-03-12 02:46:32 +01:00
2022-03-18 01:10:47 +01:00
//
// Playback Session Routes
//
2022-06-04 19:44:42 +02:00
this . router . get ( '/sessions' , SessionController . getAllWithUserData . bind ( this ) )
2022-08-13 19:24:19 +02:00
this . router . delete ( '/sessions/:id' , SessionController . middleware . bind ( this ) , SessionController . delete . bind ( this ) )
2023-04-09 01:01:24 +02:00
this . router . get ( '/sessions/open' , SessionController . getOpenSessions . bind ( this ) )
2023-02-05 23:52:17 +01:00
this . router . post ( '/session/local' , SessionController . syncLocal . bind ( this ) )
this . router . post ( '/session/local-all' , SessionController . syncLocalSessions . bind ( this ) )
2022-08-13 19:24:19 +02:00
// TODO: Update these endpoints because they are only for open playback sessions
this . router . get ( '/session/:id' , SessionController . openSessionMiddleware . bind ( this ) , SessionController . getOpenSession . bind ( this ) )
this . router . post ( '/session/:id/sync' , SessionController . openSessionMiddleware . bind ( this ) , SessionController . sync . bind ( this ) )
this . router . post ( '/session/:id/close' , SessionController . openSessionMiddleware . bind ( this ) , SessionController . close . bind ( this ) )
2022-03-18 01:10:47 +01:00
2022-03-19 16:13:10 +01:00
//
// Podcast Routes
//
this . router . post ( '/podcasts' , PodcastController . create . bind ( this ) )
this . router . post ( '/podcasts/feed' , PodcastController . getPodcastFeed . bind ( this ) )
2023-05-28 22:10:34 +02:00
this . router . post ( '/podcasts/opml' , PodcastController . getFeedsFromOPMLText . bind ( this ) )
2022-05-02 21:41:59 +02:00
this . router . get ( '/podcasts/:id/checknew' , PodcastController . middleware . bind ( this ) , PodcastController . checkNewEpisodes . bind ( this ) )
this . router . get ( '/podcasts/:id/downloads' , PodcastController . middleware . bind ( this ) , PodcastController . getEpisodeDownloads . bind ( this ) )
this . router . get ( '/podcasts/:id/clear-queue' , PodcastController . middleware . bind ( this ) , PodcastController . clearEpisodeDownloadQueue . bind ( this ) )
2022-07-31 20:12:37 +02:00
this . router . get ( '/podcasts/:id/search-episode' , PodcastController . middleware . bind ( this ) , PodcastController . findEpisode . bind ( this ) )
2022-05-02 21:41:59 +02:00
this . router . post ( '/podcasts/:id/download-episodes' , PodcastController . middleware . bind ( this ) , PodcastController . downloadEpisodes . bind ( this ) )
2023-01-05 01:13:46 +01:00
this . router . post ( '/podcasts/:id/match-episodes' , PodcastController . middleware . bind ( this ) , PodcastController . quickMatchEpisodes . bind ( this ) )
2023-03-04 20:04:55 +01:00
this . router . get ( '/podcasts/:id/episode/:episodeId' , PodcastController . middleware . bind ( this ) , PodcastController . getEpisode . bind ( this ) )
2022-05-02 21:41:59 +02:00
this . router . patch ( '/podcasts/:id/episode/:episodeId' , PodcastController . middleware . bind ( this ) , PodcastController . updateEpisode . bind ( this ) )
2022-05-25 01:38:25 +02:00
this . router . delete ( '/podcasts/:id/episode/:episodeId' , PodcastController . middleware . bind ( this ) , PodcastController . removeEpisode . bind ( this ) )
2022-03-19 16:13:10 +01:00
2022-09-22 01:01:10 +02:00
//
2022-12-26 23:58:36 +01:00
// Notification Routes (Admin and up)
2022-09-22 01:01:10 +02:00
//
this . router . get ( '/notifications' , NotificationController . middleware . bind ( this ) , NotificationController . get . bind ( this ) )
this . router . patch ( '/notifications' , NotificationController . middleware . bind ( this ) , NotificationController . update . bind ( this ) )
2022-09-23 01:12:48 +02:00
this . router . get ( '/notificationdata' , NotificationController . middleware . bind ( this ) , NotificationController . getData . bind ( this ) )
2022-09-24 23:15:16 +02:00
this . router . get ( '/notifications/test' , NotificationController . middleware . bind ( this ) , NotificationController . fireTestEvent . bind ( this ) )
2022-09-24 01:10:03 +02:00
this . router . post ( '/notifications' , NotificationController . middleware . bind ( this ) , NotificationController . createNotification . bind ( this ) )
this . router . delete ( '/notifications/:id' , NotificationController . middleware . bind ( this ) , NotificationController . deleteNotification . bind ( this ) )
this . router . patch ( '/notifications/:id' , NotificationController . middleware . bind ( this ) , NotificationController . updateNotification . bind ( this ) )
this . router . get ( '/notifications/:id/test' , NotificationController . middleware . bind ( this ) , NotificationController . sendNotificationTest . bind ( this ) )
2022-09-22 01:01:10 +02:00
2023-05-30 00:38:38 +02:00
//
// Email Routes (Admin and up)
//
this . router . get ( '/emails/settings' , EmailController . middleware . bind ( this ) , EmailController . getSettings . bind ( this ) )
this . router . patch ( '/emails/settings' , EmailController . middleware . bind ( this ) , EmailController . updateSettings . bind ( this ) )
this . router . post ( '/emails/test' , EmailController . middleware . bind ( this ) , EmailController . sendTest . bind ( this ) )
this . router . post ( '/emails/ereader-devices' , EmailController . middleware . bind ( this ) , EmailController . updateEReaderDevices . bind ( this ) )
this . router . post ( '/emails/send-ebook-to-device' , EmailController . middleware . bind ( this ) , EmailController . sendEBookToDevice . bind ( this ) )
2022-11-19 20:28:06 +01:00
//
// Search Routes
//
this . router . get ( '/search/covers' , SearchController . findCovers . bind ( this ) )
this . router . get ( '/search/books' , SearchController . findBooks . bind ( this ) )
this . router . get ( '/search/podcast' , SearchController . findPodcasts . bind ( this ) )
this . router . get ( '/search/authors' , SearchController . findAuthor . bind ( this ) )
this . router . get ( '/search/chapters' , SearchController . findChapters . bind ( this ) )
2023-01-07 20:05:33 +01:00
this . router . get ( '/search/tracks' , SearchController . findMusicTrack . bind ( this ) )
2022-11-19 20:28:06 +01:00
//
2022-12-26 23:58:36 +01:00
// Cache Routes (Admin and up)
2022-11-19 20:28:06 +01:00
//
this . router . post ( '/cache/purge' , CacheController . purgeCache . bind ( this ) )
this . router . post ( '/cache/items/purge' , CacheController . purgeItemsCache . bind ( this ) )
//
2022-12-26 23:58:36 +01:00
// Tools Routes (Admin and up)
2022-11-19 20:28:06 +01:00
//
2023-04-02 23:13:18 +02:00
this . router . post ( '/tools/item/:id/encode-m4b' , ToolsController . middleware . bind ( this ) , ToolsController . encodeM4b . bind ( this ) )
this . router . delete ( '/tools/item/:id/encode-m4b' , ToolsController . middleware . bind ( this ) , ToolsController . cancelM4bEncode . bind ( this ) )
this . router . post ( '/tools/item/:id/embed-metadata' , ToolsController . middleware . bind ( this ) , ToolsController . embedAudioFileMetadata . bind ( this ) )
this . router . post ( '/tools/batch/embed-metadata' , ToolsController . middleware . bind ( this ) , ToolsController . batchEmbedMetadata . bind ( this ) )
2022-11-19 20:28:06 +01:00
2022-12-26 23:58:36 +01:00
//
// RSS Feed Routes (Admin and up)
//
this . router . post ( '/feeds/item/:itemId/open' , RSSFeedController . middleware . bind ( this ) , RSSFeedController . openRSSFeedForItem . bind ( this ) )
2022-12-27 00:48:39 +01:00
this . router . post ( '/feeds/collection/:collectionId/open' , RSSFeedController . middleware . bind ( this ) , RSSFeedController . openRSSFeedForCollection . bind ( this ) )
2022-12-31 23:58:19 +01:00
this . router . post ( '/feeds/series/:seriesId/open' , RSSFeedController . middleware . bind ( this ) , RSSFeedController . openRSSFeedForSeries . bind ( this ) )
2022-12-26 23:58:36 +01:00
this . router . post ( '/feeds/:id/close' , RSSFeedController . middleware . bind ( this ) , RSSFeedController . closeRSSFeed . bind ( this ) )
2022-03-12 02:46:32 +01:00
//
// Misc Routes
//
2022-03-18 17:51:55 +01:00
this . router . post ( '/upload' , MiscController . handleUpload . bind ( this ) )
2022-10-02 21:16:17 +02:00
this . router . get ( '/tasks' , MiscController . getTasks . bind ( this ) )
2022-10-02 21:46:48 +02:00
this . router . patch ( '/settings' , MiscController . updateServerSettings . bind ( this ) )
2022-03-18 17:51:55 +01:00
this . router . post ( '/authorize' , MiscController . authorize . bind ( this ) )
2022-03-20 12:29:08 +01:00
this . router . get ( '/tags' , MiscController . getAllTags . bind ( this ) )
2022-12-18 21:17:52 +01:00
this . router . post ( '/tags/rename' , MiscController . renameTag . bind ( this ) )
this . router . delete ( '/tags/:tag' , MiscController . deleteTag . bind ( this ) )
2022-12-18 21:52:53 +01:00
this . router . get ( '/genres' , MiscController . getAllGenres . bind ( this ) )
this . router . post ( '/genres/rename' , MiscController . renameGenre . bind ( this ) )
this . router . delete ( '/genres/:genre' , MiscController . deleteGenre . bind ( this ) )
2022-08-02 01:06:22 +02:00
this . router . post ( '/validate-cron' , MiscController . validateCronExpression . bind ( this ) )
2021-09-04 21:17:26 +02:00
}
2021-10-05 05:11:42 +02:00
async getDirectories ( dir , relpath , excludedDirs , level = 0 ) {
try {
2022-11-24 23:35:26 +01:00
const paths = await fs . readdir ( dir )
2021-10-05 05:11:42 +02:00
2022-11-24 23:35:26 +01:00
let dirs = await Promise . all ( paths . map ( async dirname => {
const fullPath = Path . join ( dir , dirname )
const path = Path . join ( relpath , dirname )
2021-10-05 05:11:42 +02:00
2022-11-24 23:35:26 +01:00
const isDir = ( await fs . lstat ( fullPath ) ) . isDirectory ( )
2021-10-11 02:29:22 +02:00
if ( isDir && ! excludedDirs . includes ( path ) && dirname !== 'node_modules' ) {
2021-10-05 05:11:42 +02:00
return {
path ,
dirname ,
fullPath ,
level ,
dirs : level < 4 ? ( await this . getDirectories ( fullPath , path , excludedDirs , level + 1 ) ) : [ ]
}
} else {
return false
}
} ) )
dirs = dirs . filter ( d => d )
return dirs
} catch ( error ) {
Logger . error ( 'Failed to readdir' , dir , error )
return [ ]
}
}
2021-11-22 03:00:40 +01:00
//
// Helper Methods
//
2022-05-04 02:16:16 +02:00
userJsonWithItemProgressDetails ( user , hideRootToken = false ) {
2023-03-29 21:56:50 +02:00
const json = user . toJSONForBrowser ( hideRootToken )
2021-11-22 03:00:40 +01:00
2022-03-26 17:59:34 +01:00
json . mediaProgress = json . mediaProgress . map ( lip => {
2022-11-24 23:35:26 +01:00
const libraryItem = this . db . libraryItems . find ( li => li . id === lip . libraryItemId )
2022-03-18 01:10:47 +01:00
if ( ! libraryItem ) {
2022-09-26 00:11:39 +02:00
Logger . warn ( '[ApiRouter] Library item not found for users progress ' + lip . libraryItemId )
lip . media = null
} else {
if ( lip . episodeId ) {
const episode = libraryItem . mediaType === 'podcast' ? libraryItem . media . getEpisode ( lip . episodeId ) : null
if ( ! episode ) {
Logger . warn ( ` [ApiRouter] Episode ${ lip . episodeId } not found for user media progress, podcast: ${ libraryItem . media . metadata . title } ` )
lip . media = null
} else {
lip . media = libraryItem . media . toJSONExpanded ( )
lip . episode = episode . toJSON ( )
}
} else {
lip . media = libraryItem . media . toJSONExpanded ( )
}
2021-11-22 03:00:40 +01:00
}
2022-03-18 01:10:47 +01:00
return lip
} ) . filter ( lip => ! ! lip )
2021-11-22 03:00:40 +01:00
return json
2021-11-13 02:43:16 +01:00
}
2022-03-13 00:45:32 +01:00
async handleDeleteLibraryItem ( libraryItem ) {
// Remove libraryItem from users
2021-11-22 03:00:40 +01:00
for ( let i = 0 ; i < this . db . users . length ; i ++ ) {
2022-11-24 23:35:26 +01:00
const user = this . db . users [ i ]
if ( user . removeMediaProgressForLibraryItem ( libraryItem . id ) ) {
2021-11-22 03:00:40 +01:00
await this . db . updateEntity ( 'user' , user )
}
}
2022-11-24 23:35:26 +01:00
// TODO: Remove open sessions for library item
2021-11-22 03:00:40 +01:00
2022-12-31 23:58:19 +01:00
if ( libraryItem . isBook ) {
// remove book from collections
const collectionsWithBook = this . db . collections . filter ( c => c . books . includes ( libraryItem . id ) )
for ( let i = 0 ; i < collectionsWithBook . length ; i ++ ) {
const collection = collectionsWithBook [ i ]
collection . removeBook ( libraryItem . id )
await this . db . updateEntity ( 'collection' , collection )
SocketAuthority . emitter ( 'collection_updated' , collection . toJSONExpanded ( this . db . libraryItems ) )
}
// Check remove empty series
await this . checkRemoveEmptySeries ( libraryItem . media . metadata . series , libraryItem . id )
2022-11-27 21:49:21 +01:00
}
// remove item from playlists
const playlistsWithItem = this . db . playlists . filter ( p => p . hasItemsForLibraryItem ( libraryItem . id ) )
for ( let i = 0 ; i < playlistsWithItem . length ; i ++ ) {
const playlist = playlistsWithItem [ i ]
playlist . removeItemsForLibraryItem ( libraryItem . id )
// If playlist is now empty then remove it
if ( ! playlist . items . length ) {
Logger . info ( ` [ApiRouter] Playlist " ${ playlist . name } " has no more items - removing it ` )
await this . db . removeEntity ( 'playlist' , playlist . id )
SocketAuthority . clientEmitter ( playlist . userId , 'playlist_removed' , playlist . toJSONExpanded ( this . db . libraryItems ) )
} else {
await this . db . updateEntity ( 'playlist' , playlist )
SocketAuthority . clientEmitter ( playlist . userId , 'playlist_updated' , playlist . toJSONExpanded ( this . db . libraryItems ) )
}
2021-11-13 02:43:16 +01:00
}
2021-11-22 03:00:40 +01:00
2022-12-31 21:08:34 +01:00
// Close rss feed - remove from db and emit socket event
await this . rssFeedManager . closeFeedForEntityId ( libraryItem . id )
2021-12-13 00:15:37 +01:00
// purge cover cache
2022-03-13 00:45:32 +01:00
if ( libraryItem . media . coverPath ) {
await this . cacheManager . purgeCoverCache ( libraryItem . id )
2021-12-13 00:15:37 +01:00
}
2023-04-16 23:23:13 +02:00
const itemMetadataPath = Path . join ( global . MetadataPath , 'items' , libraryItem . id )
if ( await fs . pathExists ( itemMetadataPath ) ) {
Logger . debug ( ` [ApiRouter] Removing item metadata path " ${ itemMetadataPath } " ` )
await fs . remove ( itemMetadataPath )
}
2022-03-13 00:45:32 +01:00
await this . db . removeLibraryItem ( libraryItem . id )
2022-11-24 23:35:26 +01:00
SocketAuthority . emitter ( 'item_removed' , libraryItem . toJSONExpanded ( ) )
2021-11-22 03:00:40 +01:00
}
2022-12-31 23:58:19 +01:00
async checkRemoveEmptySeries ( seriesToCheck , excludeLibraryItemId = null ) {
if ( ! seriesToCheck || ! seriesToCheck . length ) return
for ( const series of seriesToCheck ) {
const otherLibraryItemsInSeries = this . db . libraryItems . filter ( li => li . id !== excludeLibraryItemId && li . isBook && li . media . metadata . hasSeries ( series . id ) )
if ( ! otherLibraryItemsInSeries . length ) {
// Close open RSS feed for series
await this . rssFeedManager . closeFeedForEntityId ( series . id )
Logger . debug ( ` [ApiRouter] Series " ${ series . name } " is now empty. Removing series ` )
await this . db . removeEntity ( 'series' , series . id )
// TODO: Socket events for series?
}
}
}
2021-11-22 03:00:40 +01:00
async getUserListeningSessionsHelper ( userId ) {
2022-11-24 23:35:26 +01:00
const userSessions = await this . db . selectUserSessions ( userId )
2022-03-18 01:10:47 +01:00
return userSessions . sort ( ( a , b ) => b . updatedAt - a . updatedAt )
2021-11-13 02:43:16 +01:00
}
2022-06-04 19:44:42 +02:00
async getAllSessionsWithUserData ( ) {
2022-11-24 23:35:26 +01:00
const sessions = await this . db . getAllSessions ( )
2022-06-04 19:44:42 +02:00
sessions . sort ( ( a , b ) => b . updatedAt - a . updatedAt )
return sessions . map ( se => {
2022-11-24 23:35:26 +01:00
const user = this . db . users . find ( u => u . id === se . userId )
return {
2022-06-04 19:44:42 +02:00
... se ,
user : user ? { id : user . id , username : user . username } : null
}
} )
}
2021-11-13 02:43:16 +01:00
async getUserListeningStatsHelpers ( userId ) {
const today = date . format ( new Date ( ) , 'YYYY-MM-DD' )
2022-11-24 23:35:26 +01:00
const listeningSessions = await this . getUserListeningSessionsHelper ( userId )
const listeningStats = {
2021-11-13 02:43:16 +01:00
totalTime : 0 ,
2022-03-18 01:10:47 +01:00
items : { } ,
2021-11-13 02:43:16 +01:00
days : { } ,
dayOfWeek : { } ,
2021-12-29 22:53:19 +01:00
today : 0 ,
recentSessions : listeningSessions . slice ( 0 , 10 )
2021-11-13 02:43:16 +01:00
}
listeningSessions . forEach ( ( s ) => {
2022-11-24 23:35:26 +01:00
let sessionTimeListening = s . timeListening
2022-04-21 01:16:27 +02:00
if ( typeof sessionTimeListening == 'string' ) {
sessionTimeListening = Number ( sessionTimeListening )
}
2021-11-13 02:43:16 +01:00
if ( s . dayOfWeek ) {
if ( ! listeningStats . dayOfWeek [ s . dayOfWeek ] ) listeningStats . dayOfWeek [ s . dayOfWeek ] = 0
2022-04-21 01:16:27 +02:00
listeningStats . dayOfWeek [ s . dayOfWeek ] += sessionTimeListening
2021-11-13 02:43:16 +01:00
}
2022-04-21 01:16:27 +02:00
if ( s . date && sessionTimeListening > 0 ) {
2021-11-13 02:43:16 +01:00
if ( ! listeningStats . days [ s . date ] ) listeningStats . days [ s . date ] = 0
2022-04-21 01:16:27 +02:00
listeningStats . days [ s . date ] += sessionTimeListening
2021-11-13 02:43:16 +01:00
if ( s . date === today ) {
2022-04-21 01:16:27 +02:00
listeningStats . today += sessionTimeListening
2021-11-13 02:43:16 +01:00
}
}
2022-03-18 01:10:47 +01:00
if ( ! listeningStats . items [ s . libraryItemId ] ) {
listeningStats . items [ s . libraryItemId ] = {
id : s . libraryItemId ,
2022-04-21 01:16:27 +02:00
timeListening : sessionTimeListening ,
2022-03-18 01:10:47 +01:00
mediaMetadata : s . mediaMetadata ,
2021-12-29 22:53:19 +01:00
lastUpdate : s . lastUpdate
}
} else {
2022-04-21 01:16:27 +02:00
listeningStats . items [ s . libraryItemId ] . timeListening += sessionTimeListening
2021-12-29 22:53:19 +01:00
}
2021-11-13 02:43:16 +01:00
2022-04-21 01:16:27 +02:00
listeningStats . totalTime += sessionTimeListening
2021-11-13 02:43:16 +01:00
} )
return listeningStats
}
2021-12-13 00:15:37 +01:00
2022-03-13 23:10:48 +01:00
async createAuthorsAndSeriesForItemUpdate ( mediaPayload ) {
if ( mediaPayload . metadata ) {
2022-11-24 23:35:26 +01:00
const mediaMetadata = mediaPayload . metadata
2022-03-13 23:10:48 +01:00
// Create new authors if in payload
if ( mediaMetadata . authors && mediaMetadata . authors . length ) {
2022-11-24 23:35:26 +01:00
const newAuthors = [ ]
2022-03-13 23:10:48 +01:00
for ( let i = 0 ; i < mediaMetadata . authors . length ; i ++ ) {
2023-04-01 00:04:26 +02:00
const authorName = ( mediaMetadata . authors [ i ] . name || '' ) . trim ( )
if ( ! authorName ) {
Logger . error ( ` [ApiRouter] Invalid author object, no name ` , mediaMetadata . authors [ i ] )
continue
}
if ( ! mediaMetadata . authors [ i ] . id || mediaMetadata . authors [ i ] . id . startsWith ( 'new' ) ) {
let author = this . db . authors . find ( au => au . checkNameEquals ( authorName ) )
2022-03-13 23:10:48 +01:00
if ( ! author ) {
author = new Author ( )
author . setData ( mediaMetadata . authors [ i ] )
2022-03-18 01:10:47 +01:00
Logger . debug ( ` [ApiRouter] Created new author " ${ author . name } " ` )
2022-03-13 23:10:48 +01:00
newAuthors . push ( author )
}
// Update ID in original payload
mediaMetadata . authors [ i ] . id = author . id
}
}
if ( newAuthors . length ) {
await this . db . insertEntities ( 'author' , newAuthors )
2022-12-22 23:26:11 +01:00
SocketAuthority . emitter ( 'authors_added' , newAuthors . map ( au => au . toJSON ( ) ) )
2022-03-13 23:10:48 +01:00
}
}
// Create new series if in payload
if ( mediaMetadata . series && mediaMetadata . series . length ) {
2022-11-24 23:35:26 +01:00
const newSeries = [ ]
2022-03-13 23:10:48 +01:00
for ( let i = 0 ; i < mediaMetadata . series . length ; i ++ ) {
2023-04-01 00:04:26 +02:00
const seriesName = ( mediaMetadata . series [ i ] . name || '' ) . trim ( )
if ( ! seriesName ) {
Logger . error ( ` [ApiRouter] Invalid series object, no name ` , mediaMetadata . series [ i ] )
continue
}
if ( ! mediaMetadata . series [ i ] . id || mediaMetadata . series [ i ] . id . startsWith ( 'new' ) ) {
let seriesItem = this . db . series . find ( se => se . checkNameEquals ( seriesName ) )
2022-03-13 23:10:48 +01:00
if ( ! seriesItem ) {
seriesItem = new Series ( )
seriesItem . setData ( mediaMetadata . series [ i ] )
2022-03-18 01:10:47 +01:00
Logger . debug ( ` [ApiRouter] Created new series " ${ seriesItem . name } " ` )
2022-03-13 23:10:48 +01:00
newSeries . push ( seriesItem )
}
// Update ID in original payload
mediaMetadata . series [ i ] . id = seriesItem . id
}
}
if ( newSeries . length ) {
await this . db . insertEntities ( 'series' , newSeries )
2022-12-22 23:26:11 +01:00
SocketAuthority . emitter ( 'multiple_series_added' , newSeries . map ( se => se . toJSON ( ) ) )
2022-03-13 23:10:48 +01:00
}
}
}
}
2021-08-18 00:01:11 +02:00
}
2023-02-27 03:56:07 +01:00
module . exports = ApiRouter