Add:RSS feed for series & cleanup empty series from db #1265

This commit is contained in:
advplyr 2022-12-31 16:58:19 -06:00
parent a364fe5031
commit 70ba2f7850
14 changed files with 282 additions and 32 deletions

View file

@ -375,6 +375,9 @@ class LibraryController {
// api/libraries/:id/series
async getAllSeriesForLibrary(req, res) {
const libraryItems = req.libraryItems
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
const payload = {
results: [],
total: 0,
@ -383,7 +386,8 @@ class LibraryController {
sortBy: req.query.sort,
sortDesc: req.query.desc === '1',
filterBy: req.query.filter,
minified: req.query.minified === '1'
minified: req.query.minified === '1',
include: include.join(',')
}
let series = libraryHelpers.getSeriesFromBooks(libraryItems, this.db.series, null, payload.filterBy, req.user, payload.minified)
@ -408,10 +412,19 @@ class LibraryController {
payload.total = series.length
if (payload.limit) {
var startIndex = payload.page * payload.limit
const startIndex = payload.page * payload.limit
series = series.slice(startIndex, startIndex + payload.limit)
}
// add rssFeed when "include=rssfeed" is in query string
if (include.includes('rssfeed')) {
series = series.map((se) => {
const feedData = this.rssFeedManager.findFeedForEntityId(se.id)
se.rssFeed = feedData?.toJSONMinified() || null
return se
})
}
payload.results = series
res.json(payload)
}
@ -442,7 +455,7 @@ class LibraryController {
if (include.includes('rssfeed')) {
const feedData = this.rssFeedManager.findFeedForEntityId(c.id)
expanded.rssFeed = feedData ? feedData.toJSONMinified() : null
expanded.rssFeed = feedData?.toJSONMinified() || null
}
return expanded

View file

@ -92,10 +92,23 @@ class LibraryItemController {
}
}
// Book specific - Get all series being removed from this item
let seriesRemoved = []
if (libraryItem.isBook && mediaPayload.metadata?.series) {
const seriesIdsInUpdate = (mediaPayload.metadata?.series || []).map(se => se.id)
seriesRemoved = libraryItem.media.metadata.series.filter(se => !seriesIdsInUpdate.includes(se.id))
}
const hasUpdates = libraryItem.media.update(mediaPayload)
if (hasUpdates) {
libraryItem.updatedAt = Date.now()
if (seriesRemoved.length) {
// Check remove empty series
Logger.debug(`[LibraryItemController] Series was removed from book. Check if series is now empty.`)
await this.checkRemoveEmptySeries(seriesRemoved)
}
if (isPodcastAutoDownloadUpdated) {
this.cronManager.checkUpdatePodcastCron(libraryItem)
}

View file

@ -75,6 +75,41 @@ class RSSFeedController {
})
}
// POST: api/feeds/series/:seriesId/open
async openRSSFeedForSeries(req, res) {
const options = req.body || {}
const series = this.db.series.find(se => se.id === req.params.seriesId)
if (!series) return res.sendStatus(404)
// Check request body options exist
if (!options.serverAddress || !options.slug) {
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 (this.rssFeedManager.feeds[options.slug]) {
Logger.error(`[RSSFeedController] Cannot open RSS feed because slug "${options.slug}" is already in use`)
return res.status(400).send('Slug already in use')
}
const seriesJson = series.toJSON()
// Get books in series that have audio tracks
seriesJson.books = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(series.id) && li.media.tracks.length)
// 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`)
return res.status(400).send('Series has no audio tracks')
}
const feed = await this.rssFeedManager.openFeedForSeries(req.user, seriesJson, req.body)
res.json({
feed: feed.toJSONMinified()
})
}
// POST: api/feeds/:id/close
async closeRSSFeed(req, res) {
await this.rssFeedManager.closeRssFeed(req.params.id)

View file

@ -5,15 +5,15 @@ class SeriesController {
constructor() { }
async findOne(req, res) {
var include = (req.query.include || '').split(',')
const include = (req.query.include || '').split(',').map(v => v.trim()).filter(v => !!v)
var seriesJson = req.series.toJSON()
const seriesJson = req.series.toJSON()
// Add progress map with isFinished flag
if (include.includes('progress')) {
var libraryItemsInSeries = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(seriesJson.id))
var libraryItemsFinished = libraryItemsInSeries.filter(li => {
var mediaProgress = req.user.getMediaProgress(li.id)
const libraryItemsInSeries = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(seriesJson.id))
const libraryItemsFinished = libraryItemsInSeries.filter(li => {
const mediaProgress = req.user.getMediaProgress(li.id)
return mediaProgress && mediaProgress.isFinished
})
seriesJson.progress = {
@ -23,6 +23,11 @@ class SeriesController {
}
}
if (include.includes('rssfeed')) {
const feedObj = this.rssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
}
return res.json(seriesJson)
}
@ -47,7 +52,7 @@ class SeriesController {
}
middleware(req, res, next) {
var series = this.db.series.find(se => se.id === req.params.id)
const series = this.db.series.find(se => se.id === req.params.id)
if (!series) return res.sendStatus(404)
if (req.method == 'DELETE' && !req.user.canDelete) {