2021-11-22 03:00:40 +01:00
const Logger = require ( '../Logger' )
2022-11-24 22:53:58 +01:00
const SocketAuthority = require ( '../SocketAuthority' )
2022-08-14 17:24:41 +02:00
const { sort } = require ( '../libs/fastSort' )
2022-06-04 17:52:37 +02:00
const { isObject , toNumber } = require ( '../utils/index' )
2021-11-22 03:00:40 +01:00
class MeController {
constructor ( ) { }
2023-02-05 23:52:17 +01:00
getCurrentUser ( req , res ) {
res . json ( req . user . toJSONForBrowser ( ) )
}
2021-11-22 03:00:40 +01:00
// GET: api/me/listening-sessions
async getListeningSessions ( req , res ) {
var listeningSessions = await this . getUserListeningSessionsHelper ( req . user . id )
2022-06-04 17:52:37 +02:00
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 )
2021-11-22 03:00:40 +01:00
}
// GET: api/me/listening-stats
async getListeningStats ( req , res ) {
var listeningStats = await this . getUserListeningStatsHelpers ( req . user . id )
res . json ( listeningStats )
}
2022-06-04 01:59:42 +02:00
// GET: api/me/progress/:id/:episodeId?
async getMediaProgress ( req , res ) {
2022-07-03 19:15:40 +02:00
const mediaProgress = req . user . getMediaProgress ( req . params . id , req . params . episodeId || null )
2022-06-04 01:59:42 +02:00
if ( ! mediaProgress ) {
return res . sendStatus ( 404 )
}
res . json ( mediaProgress )
}
2022-03-17 19:33:22 +01:00
// DELETE: api/me/progress/:id
2022-03-26 17:59:34 +01:00
async removeMediaProgress ( req , res ) {
var wasRemoved = req . user . removeMediaProgress ( req . params . id )
2022-03-17 19:33:22 +01:00
if ( ! wasRemoved ) {
return res . sendStatus ( 200 )
2021-11-22 03:00:40 +01:00
}
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2021-11-22 03:00:40 +01:00
res . sendStatus ( 200 )
}
2022-03-17 19:33:22 +01:00
// PATCH: api/me/progress/:id
2022-03-26 17:59:34 +01:00
async createUpdateMediaProgress ( req , res ) {
2022-03-14 01:34:31 +01:00
var libraryItem = this . db . libraryItems . find ( ab => ab . id === req . params . id )
if ( ! libraryItem ) {
return res . status ( 404 ) . send ( 'Item not found' )
2021-11-22 03:00:40 +01:00
}
2022-06-25 18:01:01 +02:00
2022-03-26 17:59:34 +01:00
var wasUpdated = req . user . createUpdateMediaProgress ( libraryItem , req . body )
2021-11-22 03:00:40 +01:00
if ( wasUpdated ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2021-11-22 03:00:40 +01:00
}
res . sendStatus ( 200 )
}
2022-03-26 23:41:26 +01:00
// PATCH: api/me/progress/:id/:episodeId
async createUpdateEpisodeMediaProgress ( req , res ) {
var episodeId = req . params . episodeId
var libraryItem = this . db . libraryItems . find ( ab => ab . id === req . params . id )
if ( ! libraryItem ) {
return res . status ( 404 ) . send ( 'Item not found' )
}
if ( ! libraryItem . media . episodes . find ( ep => ep . id === episodeId ) ) {
Logger . error ( ` [MeController] removeEpisode episode ${ episodeId } not found for item ${ libraryItem . id } ` )
return res . status ( 404 ) . send ( 'Episode not found' )
}
var wasUpdated = req . user . createUpdateMediaProgress ( libraryItem , req . body , episodeId )
if ( wasUpdated ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-03-26 23:41:26 +01:00
}
res . sendStatus ( 200 )
}
2022-03-17 19:33:22 +01:00
// PATCH: api/me/progress/batch/update
2022-03-26 17:59:34 +01:00
async batchUpdateMediaProgress ( req , res ) {
2022-03-17 19:33:22 +01:00
var itemProgressPayloads = req . body
if ( ! itemProgressPayloads || ! itemProgressPayloads . length ) {
2022-11-23 02:15:36 +01:00
return res . status ( 400 ) . send ( 'Missing request payload' )
2021-11-22 03:00:40 +01:00
}
var shouldUpdate = false
2022-03-17 19:33:22 +01:00
itemProgressPayloads . forEach ( ( itemProgress ) => {
2022-08-28 21:47:31 +02:00
var libraryItem = this . db . libraryItems . find ( li => li . id === itemProgress . libraryItemId ) // Make sure this library item exists
2022-03-14 01:34:31 +01:00
if ( libraryItem ) {
2022-08-28 21:47:31 +02:00
var wasUpdated = req . user . createUpdateMediaProgress ( libraryItem , itemProgress , itemProgress . episodeId )
2021-11-22 03:00:40 +01:00
if ( wasUpdated ) shouldUpdate = true
2022-03-17 19:33:22 +01:00
} else {
2022-03-26 17:59:34 +01:00
Logger . error ( ` [MeController] batchUpdateMediaProgress: Library Item does not exist ${ itemProgress . id } ` )
2021-11-22 03:00:40 +01:00
}
} )
if ( shouldUpdate ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2021-11-22 03:00:40 +01:00
}
res . sendStatus ( 200 )
}
2022-03-18 02:28:04 +01:00
// POST: api/me/item/:id/bookmark
async createBookmark ( req , res ) {
var libraryItem = this . db . libraryItems . find ( li => li . id === req . params . id )
if ( ! libraryItem ) return res . sendStatus ( 404 )
const { time , title } = req . body
var bookmark = req . user . createBookmark ( libraryItem . id , time , title )
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-03-18 02:28:04 +01:00
res . json ( bookmark )
}
// PATCH: api/me/item/:id/bookmark
async updateBookmark ( req , res ) {
var libraryItem = this . db . libraryItems . find ( li => li . id === req . params . id )
if ( ! libraryItem ) return res . sendStatus ( 404 )
const { time , title } = req . body
if ( ! req . user . findBookmark ( libraryItem . id , time ) ) {
Logger . error ( ` [MeController] updateBookmark not found ` )
return res . sendStatus ( 404 )
}
var bookmark = req . user . updateBookmark ( libraryItem . id , time , title )
if ( ! bookmark ) return res . sendStatus ( 500 )
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-03-18 02:28:04 +01:00
res . json ( bookmark )
}
// DELETE: api/me/item/:id/bookmark/:time
async removeBookmark ( req , res ) {
var libraryItem = this . db . libraryItems . find ( li => li . id === req . params . id )
if ( ! libraryItem ) return res . sendStatus ( 404 )
var time = Number ( req . params . time )
if ( isNaN ( time ) ) return res . sendStatus ( 500 )
if ( ! req . user . findBookmark ( libraryItem . id , time ) ) {
Logger . error ( ` [MeController] removeBookmark not found ` )
return res . sendStatus ( 404 )
}
req . user . removeBookmark ( libraryItem . id , time )
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-03-18 02:28:04 +01:00
res . sendStatus ( 200 )
}
2021-11-22 03:00:40 +01:00
// PATCH: api/me/password
updatePassword ( req , res ) {
2022-04-30 01:38:13 +02:00
if ( req . user . isGuest ) {
Logger . error ( ` [MeController] Guest user attempted to change password ` , req . user . username )
return res . sendStatus ( 500 )
}
2021-11-22 03:00:40 +01:00
this . auth . userChangePassword ( req , res )
}
2023-02-05 23:52:17 +01:00
// TODO: Deprecated. Removed from Android. Only used in iOS app now.
2022-04-10 00:56:51 +02:00
// POST: api/me/sync-local-progress
async syncLocalMediaProgress ( req , res ) {
if ( ! req . body . localMediaProgress ) {
Logger . error ( ` [MeController] syncLocalMediaProgress invalid post body ` )
return res . sendStatus ( 500 )
}
const updatedLocalMediaProgress = [ ]
var numServerProgressUpdates = 0
2023-01-28 21:46:01 +01:00
const updatedServerMediaProgress = [ ]
const localMediaProgress = req . body . localMediaProgress || [ ]
2022-07-14 02:18:49 +02:00
2022-04-10 00:56:51 +02:00
localMediaProgress . forEach ( localProgress => {
if ( ! localProgress . libraryItemId ) {
Logger . error ( ` [MeController] syncLocalMediaProgress invalid local media progress object ` , localProgress )
return
}
var libraryItem = this . db . getLibraryItem ( localProgress . libraryItemId )
if ( ! libraryItem ) {
Logger . error ( ` [MeController] syncLocalMediaProgress invalid local media progress object no library item ` , localProgress )
return
}
2023-01-28 21:46:01 +01:00
let mediaProgress = req . user . getMediaProgress ( localProgress . libraryItemId , localProgress . episodeId )
2022-04-10 00:56:51 +02:00
if ( ! mediaProgress ) {
// New media progress from mobile
Logger . debug ( ` [MeController] syncLocalMediaProgress local progress is new - creating ${ localProgress . id } ` )
req . user . createUpdateMediaProgress ( libraryItem , localProgress , localProgress . episodeId )
2023-01-28 21:46:01 +01:00
mediaProgress = req . user . getMediaProgress ( localProgress . libraryItemId , localProgress . episodeId )
updatedServerMediaProgress . push ( mediaProgress )
2022-04-10 00:56:51 +02:00
numServerProgressUpdates ++
} else if ( mediaProgress . lastUpdate < localProgress . lastUpdate ) {
Logger . debug ( ` [MeController] syncLocalMediaProgress local progress is more recent - updating ${ mediaProgress . id } ` )
req . user . createUpdateMediaProgress ( libraryItem , localProgress , localProgress . episodeId )
2023-01-28 21:46:01 +01:00
mediaProgress = req . user . getMediaProgress ( localProgress . libraryItemId , localProgress . episodeId )
updatedServerMediaProgress . push ( mediaProgress )
2022-04-10 00:56:51 +02:00
numServerProgressUpdates ++
} else if ( mediaProgress . lastUpdate > localProgress . lastUpdate ) {
2023-01-28 21:46:01 +01:00
const updateTimeDifference = mediaProgress . lastUpdate - localProgress . lastUpdate
2022-04-10 00:56:51 +02:00
Logger . debug ( ` [MeController] syncLocalMediaProgress server progress is more recent by ${ updateTimeDifference } ms - ${ mediaProgress . id } ` )
for ( const key in localProgress ) {
2022-07-14 02:18:49 +02:00
// Local media progress ID uses the local library item id and server media progress uses the library item id
if ( key !== 'id' && mediaProgress [ key ] != undefined && localProgress [ key ] !== mediaProgress [ key ] ) {
2022-04-10 00:56:51 +02:00
// Logger.debug(`[MeController] syncLocalMediaProgress key ${key} changed from ${localProgress[key]} to ${mediaProgress[key]} - ${mediaProgress.id}`)
localProgress [ key ] = mediaProgress [ key ]
}
}
updatedLocalMediaProgress . push ( localProgress )
} else {
Logger . debug ( ` [MeController] syncLocalMediaProgress server and local are in sync - ${ mediaProgress . id } ` )
}
} )
Logger . debug ( ` [MeController] syncLocalMediaProgress server updates = ${ numServerProgressUpdates } , local updates = ${ updatedLocalMediaProgress . length } ` )
if ( numServerProgressUpdates > 0 ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-04-10 00:56:51 +02:00
}
res . json ( {
numServerProgressUpdates ,
2023-01-28 21:46:01 +01:00
localProgressUpdates : updatedLocalMediaProgress , // Array of LocalMediaProgress that were updated from server (server more recent)
serverProgressUpdates : updatedServerMediaProgress // Array of MediaProgress that made updates to server (local more recent)
2022-04-10 00:56:51 +02:00
} )
}
2022-08-14 17:24:41 +02:00
// GET: api/me/items-in-progress
2023-03-25 20:07:35 +01:00
getAllLibraryItemsInProgress ( req , res ) {
2022-08-14 17:24:41 +02:00
const limit = ! isNaN ( req . query . limit ) ? Number ( req . query . limit ) || 25 : 25
2023-03-25 20:07:35 +01:00
let itemsInProgress = [ ]
2022-08-14 17:24:41 +02:00
for ( const mediaProgress of req . user . mediaProgress ) {
2023-03-25 20:07:35 +01:00
if ( ! mediaProgress . isFinished && ( mediaProgress . progress > 0 || mediaProgress . ebookProgress > 0 ) ) {
const libraryItem = this . db . getLibraryItem ( mediaProgress . libraryItemId )
2022-08-14 17:24:41 +02:00
if ( libraryItem ) {
if ( mediaProgress . episodeId && libraryItem . mediaType === 'podcast' ) {
const episode = libraryItem . media . episodes . find ( ep => ep . id === mediaProgress . episodeId )
if ( episode ) {
const libraryItemWithEpisode = {
... libraryItem . toJSONMinified ( ) ,
recentEpisode : episode . toJSON ( ) ,
progressLastUpdate : mediaProgress . lastUpdate
}
itemsInProgress . push ( libraryItemWithEpisode )
}
} else if ( ! mediaProgress . episodeId ) {
itemsInProgress . push ( {
... libraryItem . toJSONMinified ( ) ,
progressLastUpdate : mediaProgress . lastUpdate
} )
}
}
}
}
itemsInProgress = sort ( itemsInProgress ) . desc ( li => li . progressLastUpdate ) . slice ( 0 , limit )
res . json ( {
libraryItems : itemsInProgress
} )
}
2022-09-29 00:12:27 +02:00
2022-09-29 00:45:39 +02:00
// GET: api/me/series/:id/remove-from-continue-listening
async removeSeriesFromContinueListening ( req , res ) {
2022-09-29 00:12:27 +02:00
const series = this . db . series . find ( se => se . id === req . params . id )
if ( ! series ) {
2022-09-29 00:45:39 +02:00
Logger . error ( ` [MeController] removeSeriesFromContinueListening: Series ${ req . params . id } not found ` )
2022-09-29 00:12:27 +02:00
return res . sendStatus ( 404 )
}
const hasUpdated = req . user . addSeriesToHideFromContinueListening ( req . params . id )
if ( hasUpdated ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-09-29 00:12:27 +02:00
}
res . json ( req . user . toJSONForBrowser ( ) )
}
2022-09-29 00:45:39 +02:00
2022-11-16 00:20:57 +01:00
// GET: api/me/series/:id/readd-to-continue-listening
async readdSeriesFromContinueListening ( req , res ) {
const series = this . db . series . find ( se => se . id === req . params . id )
if ( ! series ) {
Logger . error ( ` [MeController] readdSeriesFromContinueListening: Series ${ req . params . id } not found ` )
return res . sendStatus ( 404 )
}
const hasUpdated = req . user . removeSeriesFromHideFromContinueListening ( req . params . id )
if ( hasUpdated ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-11-16 00:20:57 +01:00
}
res . json ( req . user . toJSONForBrowser ( ) )
}
2022-09-29 00:45:39 +02:00
// GET: api/me/progress/:id/remove-from-continue-listening
async removeItemFromContinueListening ( req , res ) {
const hasUpdated = req . user . removeProgressFromContinueListening ( req . params . id )
if ( hasUpdated ) {
await this . db . updateEntity ( 'user' , req . user )
2022-11-24 22:53:58 +01:00
SocketAuthority . clientEmitter ( req . user . id , 'user_updated' , req . user . toJSONForBrowser ( ) )
2022-09-29 00:45:39 +02:00
}
res . json ( req . user . toJSONForBrowser ( ) )
}
2021-11-22 03:00:40 +01:00
}
module . exports = new MeController ( )