Add:Daily cron that closes stale open playback sessions

This commit is contained in:
advplyr 2024-07-04 12:00:54 -05:00
parent 43217657d7
commit fed5ff4863
5 changed files with 56 additions and 2 deletions

View File

@ -74,7 +74,7 @@ class Server {
this.podcastManager = new PodcastManager(this.watcher, this.notificationManager) this.podcastManager = new PodcastManager(this.watcher, this.notificationManager)
this.audioMetadataManager = new AudioMetadataMangaer() this.audioMetadataManager = new AudioMetadataMangaer()
this.rssFeedManager = new RssFeedManager() this.rssFeedManager = new RssFeedManager()
this.cronManager = new CronManager(this.podcastManager) this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager)
this.apiCacheManager = new ApiCacheManager() this.apiCacheManager = new ApiCacheManager()
this.binaryManager = new BinaryManager() this.binaryManager = new BinaryManager()

View File

@ -233,6 +233,7 @@ class ShareController {
} }
playbackSession.currentTime = Math.min(currentTime, playbackSession.duration) playbackSession.currentTime = Math.min(currentTime, playbackSession.duration)
playbackSession.updatedAt = Date.now()
Logger.debug(`[ShareController] Update share playback session ${req.cookies.share_session_id} currentTime: ${playbackSession.currentTime}`) Logger.debug(`[ShareController] Update share playback session ${req.cookies.share_session_id} currentTime: ${playbackSession.currentTime}`)
res.sendStatus(204) res.sendStatus(204)
} }

View File

@ -4,9 +4,14 @@ const Logger = require('../Logger')
const Database = require('../Database') const Database = require('../Database')
const LibraryScanner = require('../scanner/LibraryScanner') const LibraryScanner = require('../scanner/LibraryScanner')
const ShareManager = require('./ShareManager')
class CronManager { class CronManager {
constructor(podcastManager) { constructor(podcastManager, playbackSessionManager) {
/** @type {import('./PodcastManager')} */
this.podcastManager = podcastManager this.podcastManager = podcastManager
/** @type {import('./PlaybackSessionManager')} */
this.playbackSessionManager = playbackSessionManager
this.libraryScanCrons = [] this.libraryScanCrons = []
this.podcastCrons = [] this.podcastCrons = []
@ -19,10 +24,26 @@ class CronManager {
* @param {import('../objects/Library')[]} libraries * @param {import('../objects/Library')[]} libraries
*/ */
async init(libraries) { async init(libraries) {
this.initOpenSessionCleanupCron()
this.initLibraryScanCrons(libraries) this.initLibraryScanCrons(libraries)
await this.initPodcastCrons() await this.initPodcastCrons()
} }
/**
* Initialize open session cleanup cron
* Runs every day at 00:30
* Closes open share sessions that have not been updated in 24 hours
* Closes open playback sessions that have not been updated in 36 hours
* TODO: Clients should re-open the session if it is closed so that stale sessions can be closed sooner
*/
initOpenSessionCleanupCron() {
cron.schedule('30 0 * * *', async () => {
Logger.debug('[CronManager] Open session cleanup cron executing')
ShareManager.closeStaleOpenShareSessions()
await this.playbackSessionManager.closeStaleOpenSessions()
})
}
/** /**
* Initialize library scan crons * Initialize library scan crons
* @param {import('../objects/Library')[]} libraries * @param {import('../objects/Library')[]} libraries

View File

@ -21,6 +21,8 @@ class PlaybackSessionManager {
this.StreamsPath = Path.join(global.MetadataPath, 'streams') this.StreamsPath = Path.join(global.MetadataPath, 'streams')
this.oldPlaybackSessionMap = {} // TODO: Remove after updated mobile versions this.oldPlaybackSessionMap = {} // TODO: Remove after updated mobile versions
/** @type {PlaybackSession[]} */
this.sessions = [] this.sessions = []
} }
@ -346,6 +348,10 @@ class PlaybackSessionManager {
} }
} }
/**
*
* @param {string} sessionId
*/
async removeSession(sessionId) { async removeSession(sessionId) {
const session = this.sessions.find((s) => s.id === sessionId) const session = this.sessions.find((s) => s.id === sessionId)
if (!session) return if (!session) return
@ -378,5 +384,18 @@ class PlaybackSessionManager {
Logger.error(`[PlaybackSessionManager] cleanOrphanStreams failed`, error) Logger.error(`[PlaybackSessionManager] cleanOrphanStreams failed`, error)
} }
} }
/**
* Close all open sessions that have not been updated in the last 36 hours
*/
async closeStaleOpenSessions() {
const updatedAtTimeCutoff = Date.now() - 1000 * 60 * 60 * 36
const staleSessions = this.sessions.filter((session) => session.updatedAt < updatedAtTimeCutoff)
for (const session of staleSessions) {
const sessionLastUpdate = new Date(session.updatedAt)
Logger.info(`[PlaybackSessionManager] Closing stale session "${session.displayTitle}" (${session.id}) last updated at ${sessionLastUpdate}`)
await this.removeSession(session.id)
}
}
} }
module.exports = PlaybackSessionManager module.exports = PlaybackSessionManager

View File

@ -162,5 +162,18 @@ class ShareManager {
destroyMediaItemShare(mediaItemShareId) { destroyMediaItemShare(mediaItemShareId) {
return Database.models.mediaItemShare.destroy({ where: { id: mediaItemShareId } }) return Database.models.mediaItemShare.destroy({ where: { id: mediaItemShareId } })
} }
/**
* Close open share sessions that have not been updated in the last 24 hours
*/
closeStaleOpenShareSessions() {
const updatedAtTimeCutoff = Date.now() - 1000 * 60 * 60 * 24
const staleSessions = this.openSharePlaybackSessions.filter((session) => session.updatedAt < updatedAtTimeCutoff)
for (const session of staleSessions) {
const sessionLastUpdate = new Date(session.updatedAt)
Logger.info(`[PlaybackSessionManager] Closing stale session "${session.displayTitle}" (${session.id}) last updated at ${sessionLastUpdate}`)
this.closeSharePlaybackSession(session)
}
}
} }
module.exports = new ShareManager() module.exports = new ShareManager()