Skip to content

Commit

Permalink
Merge pull request #3724 from advplyr/feed_migration
Browse files Browse the repository at this point in the history
Refactor Feed model to create new feed for collection
  • Loading branch information
advplyr authored Dec 15, 2024
2 parents ca2327a + b39268c commit 6cef1e3
Show file tree
Hide file tree
Showing 25 changed files with 859 additions and 1,161 deletions.
15 changes: 0 additions & 15 deletions server/Database.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,21 +444,6 @@ class Database {
return updated
}

async createFeed(oldFeed) {
if (!this.sequelize) return false
await this.models.feed.fullCreateFromOld(oldFeed)
}

updateFeed(oldFeed) {
if (!this.sequelize) return false
return this.models.feed.fullUpdateFromOld(oldFeed)
}

async removeFeed(feedId) {
if (!this.sequelize) return false
await this.models.feed.removeById(feedId)
}

async createBulkBookAuthors(bookAuthors) {
if (!this.sequelize) return false
await this.models.bookAuthor.bulkCreate(bookAuthors)
Expand Down
9 changes: 4 additions & 5 deletions server/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ class Server {
this.playbackSessionManager = new PlaybackSessionManager()
this.podcastManager = new PodcastManager()
this.audioMetadataManager = new AudioMetadataMangaer()
this.rssFeedManager = new RssFeedManager()
this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager)
this.apiCacheManager = new ApiCacheManager()
this.binaryManager = new BinaryManager()
Expand Down Expand Up @@ -137,7 +136,7 @@ class Server {

await ShareManager.init()
await this.backupManager.init()
await this.rssFeedManager.init()
await RssFeedManager.init()

const libraries = await Database.libraryModel.getAllWithFolders()
await this.cronManager.init(libraries)
Expand Down Expand Up @@ -291,14 +290,14 @@ class Server {
// RSS Feed temp route
router.get('/feed/:slug', (req, res) => {
Logger.info(`[Server] Requesting rss feed ${req.params.slug}`)
this.rssFeedManager.getFeed(req, res)
RssFeedManager.getFeed(req, res)
})
router.get('/feed/:slug/cover*', (req, res) => {
this.rssFeedManager.getFeedCover(req, res)
RssFeedManager.getFeedCover(req, res)
})
router.get('/feed/:slug/item/:episodeId/*', (req, res) => {
Logger.debug(`[Server] Requesting rss feed episode ${req.params.slug}/${req.params.episodeId}`)
this.rssFeedManager.getFeedItem(req, res)
RssFeedManager.getFeedItem(req, res)
})

// Auth routes
Expand Down
14 changes: 12 additions & 2 deletions server/controllers/CollectionController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')

const RssFeedManager = require('../managers/RssFeedManager')
const Collection = require('../objects/Collection')

/**
Expand Down Expand Up @@ -115,6 +116,7 @@ class CollectionController {
}

// If books array is passed in then update order in collection
let collectionBooksUpdated = false
if (req.body.books?.length) {
const collectionBooks = await req.collection.getCollectionBooks({
include: {
Expand All @@ -133,9 +135,15 @@ class CollectionController {
await collectionBooks[i].update({
order: i + 1
})
wasUpdated = true
collectionBooksUpdated = true
}
}

if (collectionBooksUpdated) {
req.collection.changed('updatedAt', true)
await req.collection.save()
wasUpdated = true
}
}

const jsonExpanded = await req.collection.getOldJsonExpanded()
Expand All @@ -148,14 +156,16 @@ class CollectionController {
/**
* DELETE: /api/collections/:id
*
* @this {import('../routers/ApiRouter')}
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
const jsonExpanded = await req.collection.getOldJsonExpanded()

// Close rss feed - remove from db and emit socket event
await this.rssFeedManager.closeFeedForEntityId(req.collection.id)
await RssFeedManager.closeFeedForEntityId(req.collection.id)

await req.collection.destroy()

Expand Down
6 changes: 4 additions & 2 deletions server/controllers/LibraryController.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const LibraryScanner = require('../scanner/LibraryScanner')
const Scanner = require('../scanner/Scanner')
const Database = require('../Database')
const Watcher = require('../Watcher')
const RssFeedManager = require('../managers/RssFeedManager')

const libraryFilters = require('../utils/queries/libraryFilters')
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
const authorFilters = require('../utils/queries/authorFilters')
Expand Down Expand Up @@ -759,8 +761,8 @@ class LibraryController {
}

if (include.includes('rssfeed')) {
const feedObj = await this.rssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
const feedObj = await RssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toOldJSONMinified() || null
}

res.json(seriesJson)
Expand Down
6 changes: 4 additions & 2 deletions server/controllers/LibraryItemController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUti
const LibraryItemScanner = require('../scanner/LibraryItemScanner')
const AudioFileScanner = require('../scanner/AudioFileScanner')
const Scanner = require('../scanner/Scanner')

const RssFeedManager = require('../managers/RssFeedManager')
const CacheManager = require('../managers/CacheManager')
const CoverManager = require('../managers/CoverManager')
const ShareManager = require('../managers/ShareManager')
Expand Down Expand Up @@ -48,8 +50,8 @@ class LibraryItemController {
}

if (includeEntities.includes('rssfeed')) {
const feedData = await this.rssFeedManager.findFeedForEntityId(item.id)
item.rssFeed = feedData?.toJSONMinified() || null
const feedData = await RssFeedManager.findFeedForEntityId(item.id)
item.rssFeed = feedData?.toOldJSONMinified() || null
}

if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {
Expand Down
81 changes: 46 additions & 35 deletions server/controllers/RSSFeedController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const Database = require('../Database')
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')

const RssFeedManager = require('../managers/RssFeedManager')

/**
* @typedef RequestUserObject
Expand All @@ -22,10 +23,10 @@ class RSSFeedController {
* @param {Response} res
*/
async getAll(req, res) {
const feeds = await this.rssFeedManager.getFeeds()
const feeds = await RssFeedManager.getFeeds()
res.json({
feeds: feeds.map((f) => f.toJSON()),
minified: feeds.map((f) => f.toJSONMinified())
feeds: feeds.map((f) => f.toOldJSON()),
minified: feeds.map((f) => f.toOldJSONMinified())
})
}

Expand Down Expand Up @@ -62,12 +63,12 @@ class RSSFeedController {
}

// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await this.rssFeedManager.findFeedBySlug(reqBody.slug)) {
if (await RssFeedManager.checkExistsBySlug(reqBody.slug)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${reqBody.slug}" is already in use`)
return res.status(400).send('Slug already in use')
}

const feed = await this.rssFeedManager.openFeedForItem(req.user.id, itemExpanded, reqBody)
const feed = await RssFeedManager.openFeedForItem(req.user.id, itemExpanded, reqBody)
if (!feed) {
Logger.error(`[RSSFeedController] Failed to open RSS feed for item "${itemExpanded.media.title}"`)
return res.status(500).send('Failed to open RSS feed')
Expand All @@ -87,35 +88,37 @@ class RSSFeedController {
* @param {Response} res
*/
async openRSSFeedForCollection(req, res) {
const options = req.body || {}

const collection = await Database.collectionModel.findByPk(req.params.collectionId)
if (!collection) return res.sendStatus(404)
const reqBody = req.body || {}

// Check request body options exist
if (!options.serverAddress || !options.slug) {
if (!reqBody.serverAddress || !reqBody.slug || typeof reqBody.serverAddress !== 'string' || typeof reqBody.slug !== 'string') {
Logger.error(`[RSSFeedController] Invalid request body to open RSS feed`)
return res.status(400).send('Invalid request body')
}

// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await this.rssFeedManager.findFeedBySlug(options.slug)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${options.slug}" is already in use`)
if (await RssFeedManager.checkExistsBySlug(reqBody.slug)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${reqBody.slug}" is already in use`)
return res.status(400).send('Slug already in use')
}

const collectionExpanded = await collection.getOldJsonExpanded()
const collectionItemsWithTracks = collectionExpanded.books.filter((li) => li.media.tracks.length)
const collection = await Database.collectionModel.getExpandedById(req.params.collectionId)
if (!collection) return res.sendStatus(404)

// Check collection has audio tracks
if (!collectionItemsWithTracks.length) {
if (!collection.books.some((book) => book.includedAudioFiles.length)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed for collection "${collection.name}" because it has no audio tracks`)
return res.status(400).send('Collection has no audio tracks')
}

const feed = await this.rssFeedManager.openFeedForCollection(req.user.id, collectionExpanded, req.body)
const feed = await RssFeedManager.openFeedForCollection(req.user.id, collection, reqBody)
if (!feed) {
Logger.error(`[RSSFeedController] Failed to open RSS feed for collection "${collection.name}"`)
return res.status(500).send('Failed to open RSS feed')
}

res.json({
feed: feed.toJSONMinified()
feed: feed.toOldJSONMinified()
})
}

Expand All @@ -128,37 +131,37 @@ class RSSFeedController {
* @param {Response} res
*/
async openRSSFeedForSeries(req, res) {
const options = req.body || {}

const series = await Database.seriesModel.findByPk(req.params.seriesId)
if (!series) return res.sendStatus(404)
const reqBody = req.body || {}

// Check request body options exist
if (!options.serverAddress || !options.slug) {
if (!reqBody.serverAddress || !reqBody.slug || typeof reqBody.serverAddress !== 'string' || typeof reqBody.slug !== 'string') {
Logger.error(`[RSSFeedController] Invalid request body to open RSS feed`)
return res.status(400).send('Invalid request body')
}

// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await this.rssFeedManager.findFeedBySlug(options.slug)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${options.slug}" is already in use`)
if (await RssFeedManager.checkExistsBySlug(reqBody.slug)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${reqBody.slug}" is already in use`)
return res.status(400).send('Slug already in use')
}

const seriesJson = series.toOldJSON()

// Get books in series that have audio tracks
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter((li) => li.media.numTracks)
const series = await Database.seriesModel.getExpandedById(req.params.seriesId)
if (!series) return res.sendStatus(404)

// Check series has audio tracks
if (!seriesJson.books.length) {
Logger.error(`[RSSFeedController] Cannot open RSS feed for series "${seriesJson.name}" because it has no audio tracks`)
if (!series.books.some((book) => book.includedAudioFiles.length)) {
Logger.error(`[RSSFeedController] Cannot open RSS feed for series "${series.name}" because it has no audio tracks`)
return res.status(400).send('Series has no audio tracks')
}

const feed = await this.rssFeedManager.openFeedForSeries(req.user.id, seriesJson, req.body)
const feed = await RssFeedManager.openFeedForSeries(req.user.id, series, req.body)
if (!feed) {
Logger.error(`[RSSFeedController] Failed to open RSS feed for series "${series.name}"`)
return res.status(500).send('Failed to open RSS feed')
}

res.json({
feed: feed.toJSONMinified()
feed: feed.toOldJSONMinified()
})
}

Expand All @@ -170,8 +173,16 @@ class RSSFeedController {
* @param {RequestWithUser} req
* @param {Response} res
*/
closeRSSFeed(req, res) {
this.rssFeedManager.closeRssFeed(req, res)
async closeRSSFeed(req, res) {
const feed = await Database.feedModel.findByPk(req.params.id)
if (!feed) {
Logger.error(`[RSSFeedController] Cannot close RSS feed because feed "${req.params.id}" does not exist`)
return res.sendStatus(404)
}

await RssFeedManager.handleCloseFeed(feed)

res.sendStatus(200)
}

/**
Expand Down
7 changes: 5 additions & 2 deletions server/controllers/SeriesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')

const RssFeedManager = require('../managers/RssFeedManager')

const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')

/**
Expand Down Expand Up @@ -51,8 +54,8 @@ class SeriesController {
}

if (include.includes('rssfeed')) {
const feedObj = await this.rssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
const feedObj = await RssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toOldJSONMinified() || null
}

res.json(seriesJson)
Expand Down
Loading

0 comments on commit 6cef1e3

Please sign in to comment.