diff --git a/server/managers/RssFeedManager.js b/server/managers/RssFeedManager.js index a1160cda..5b333849 100644 --- a/server/managers/RssFeedManager.js +++ b/server/managers/RssFeedManager.js @@ -30,7 +30,7 @@ class RssFeedManager { return Object.values(this.feeds).find(feed => feed.entityId === libraryItemId) } - getFeed(req, res) { + async getFeed(req, res) { var feed = this.feeds[req.params.id] if (!feed) { Logger.error(`[RssFeedManager] Feed not found ${req.params.id}`) @@ -38,6 +38,15 @@ class RssFeedManager { return } + if (feed.entityType === 'item') { + const libraryItem = this.db.getLibraryItem(feed.entityId) + if (libraryItem && (!feed.entityUpdatedAt || libraryItem.updatedAt > feed.entityUpdatedAt)) { + Logger.debug(`[RssFeedManager] Updating RSS feed for item ${libraryItem.id} "${libraryItem.media.metadata.title}"`) + feed.updateFromItem(libraryItem) + await this.db.updateEntity('feed', feed) + } + } + var xml = feed.buildXml() res.set('Content-Type', 'text/xml') res.send(xml) diff --git a/server/objects/Feed.js b/server/objects/Feed.js index 33c72643..9e00d57c 100644 --- a/server/objects/Feed.js +++ b/server/objects/Feed.js @@ -9,6 +9,7 @@ class Feed { this.userId = null this.entityType = null this.entityId = null + this.entityUpdatedAt = null this.coverPath = null this.serverAddress = null @@ -79,6 +80,7 @@ class Feed { this.userId = userId this.entityType = 'item' this.entityId = libraryItem.id + this.entityUpdatedAt = libraryItem.updatedAt this.coverPath = media.coverPath || null this.serverAddress = serverAddress this.feedUrl = feedUrl @@ -111,6 +113,39 @@ class Feed { this.updatedAt = Date.now() } + updateFromItem(libraryItem) { + const media = libraryItem.media + const mediaMetadata = media.metadata + const isPodcast = libraryItem.mediaType === 'podcast' + const author = isPodcast ? mediaMetadata.author : mediaMetadata.authorName + + this.entityUpdatedAt = libraryItem.updatedAt + + this.meta.title = mediaMetadata.title + this.meta.description = mediaMetadata.description + this.meta.author = author + this.meta.imageUrl = media.coverPath ? `${this.serverAddress}/feed/${this.slug}/cover` : `${this.serverAddress}/Logo.png` + this.meta.explicit = !!mediaMetadata.explicit + + this.episodes = [] + if (isPodcast) { // PODCAST EPISODES + media.episodes.forEach((episode) => { + var feedEpisode = new FeedEpisode() + feedEpisode.setFromPodcastEpisode(libraryItem, this.serverAddress, this.slug, episode, this.meta) + this.episodes.push(feedEpisode) + }) + } else { // AUDIOBOOK EPISODES + media.tracks.forEach((audioTrack) => { + var feedEpisode = new FeedEpisode() + feedEpisode.setFromAudiobookTrack(libraryItem, this.serverAddress, this.slug, audioTrack, this.meta) + this.episodes.push(feedEpisode) + }) + } + + this.updatedAt = Date.now() + this.xml = null + } + buildXml() { if (this.xml) return this.xml