Remove old Feed/FeedEpisode/FeedMeta objects

This commit is contained in:
advplyr 2024-12-15 17:54:36 -06:00
parent de8a9304d2
commit b39268ccb0
17 changed files with 84 additions and 326 deletions

View File

@ -762,7 +762,7 @@ class LibraryController {
if (include.includes('rssfeed')) {
const feedObj = await RssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
seriesJson.rssFeed = feedObj?.toOldJSONMinified() || null
}
res.json(seriesJson)

View File

@ -51,7 +51,7 @@ class LibraryItemController {
if (includeEntities.includes('rssfeed')) {
const feedData = await RssFeedManager.findFeedForEntityId(item.id)
item.rssFeed = feedData?.toJSONMinified() || null
item.rssFeed = feedData?.toOldJSONMinified() || null
}
if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {

View File

@ -25,8 +25,8 @@ class RSSFeedController {
async getAll(req, res) {
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())
})
}
@ -63,7 +63,7 @@ class RSSFeedController {
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await 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')
}
@ -97,7 +97,7 @@ class RSSFeedController {
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await 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')
}
@ -140,7 +140,7 @@ class RSSFeedController {
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
if (await 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')
}

View File

@ -55,7 +55,7 @@ class SeriesController {
if (include.includes('rssfeed')) {
const feedObj = await RssFeedManager.findFeedForEntityId(seriesJson.id)
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
seriesJson.rssFeed = feedObj?.toOldJSONMinified() || null
}
res.json(seriesJson)

View File

@ -53,19 +53,29 @@ class RssFeedManager {
/**
* Find open feed for an entity (e.g. collection id, playlist id, library item id)
* @param {string} entityId
* @returns {Promise<objects.Feed>} oldFeed
* @returns {Promise<import('../models/Feed')>}
*/
findFeedForEntityId(entityId) {
return Database.feedModel.findOneOld({ entityId })
return Database.feedModel.findOne({
where: {
entityId
}
})
}
/**
* Find open feed for a slug
*
* @param {string} slug
* @returns {Promise<objects.Feed>} oldFeed
* @returns {Promise<boolean>}
*/
findFeedBySlug(slug) {
return Database.feedModel.findOneOld({ slug })
checkExistsBySlug(slug) {
return Database.feedModel
.count({
where: {
slug
}
})
.then((count) => count > 0)
}
/**
@ -169,7 +179,17 @@ class RssFeedManager {
* @param {Response} res
*/
async getFeedItem(req, res) {
const feed = await this.findFeedBySlug(req.params.slug)
const feed = await Database.feedModel.findOne({
where: {
slug: req.params.slug
},
attributes: ['id', 'slug'],
include: {
model: Database.feedEpisodeModel,
attributes: ['id', 'filePath']
}
})
if (!feed) {
Logger.debug(`[RssFeedManager] Feed not found ${req.params.slug}`)
res.sendStatus(404)
@ -191,7 +211,12 @@ class RssFeedManager {
* @param {Response} res
*/
async getFeedCover(req, res) {
const feed = await this.findFeedBySlug(req.params.slug)
const feed = await Database.feedModel.findOne({
where: {
slug: req.params.slug
},
attributes: ['coverPath']
})
if (!feed) {
Logger.debug(`[RssFeedManager] Feed not found ${req.params.slug}`)
res.sendStatus(404)
@ -338,10 +363,16 @@ class RssFeedManager {
}
}
async getFeeds() {
const feeds = await Database.models.feed.getOldFeeds()
Logger.info(`[RssFeedManager] Fetched all feeds`)
return feeds
/**
*
* @returns {Promise<import('../models/Feed').FeedExpanded[]>}
*/
getFeeds() {
return Database.feedModel.findAll({
include: {
model: Database.feedEpisodeModel
}
})
}
}
module.exports = new RssFeedManager()

View File

@ -112,7 +112,7 @@ class Collection extends Model {
// Map feed if found
if (c.feeds?.length) {
collectionExpanded.rssFeed = this.sequelize.models.feed.getOldFeed(c.feeds[0])
collectionExpanded.rssFeed = c.feeds[0].toOldJSON()
}
return collectionExpanded
@ -348,7 +348,7 @@ class Collection extends Model {
if (include?.includes('rssfeed')) {
const feeds = await this.getFeeds()
if (feeds?.length) {
collectionExpanded.rssFeed = this.sequelize.models.feed.getOldFeed(feeds[0])
collectionExpanded.rssFeed = feeds[0].toOldJSON()
}
}

View File

@ -1,6 +1,5 @@
const Path = require('path')
const { DataTypes, Model } = require('sequelize')
const oldFeed = require('../objects/Feed')
const Logger = require('../Logger')
const RSS = require('../libs/rss')
@ -74,60 +73,6 @@ class Feed extends Model {
this.feedEpisodes
}
static async getOldFeeds() {
const feeds = await this.findAll({
include: {
model: this.sequelize.models.feedEpisode
}
})
return feeds.map((f) => this.getOldFeed(f))
}
/**
* Get old feed from Feed and optionally Feed with FeedEpisodes
* @param {Feed} feedExpanded
* @returns {oldFeed}
*/
static getOldFeed(feedExpanded) {
const episodes = feedExpanded.feedEpisodes?.map((feedEpisode) => feedEpisode.getOldEpisode()) || []
// Sort episodes by pubDate. Newest to oldest for episodic, oldest to newest for serial
if (feedExpanded.podcastType === 'episodic') {
episodes.sort((a, b) => new Date(b.pubDate) - new Date(a.pubDate))
} else {
episodes.sort((a, b) => new Date(a.pubDate) - new Date(b.pubDate))
}
return new oldFeed({
id: feedExpanded.id,
slug: feedExpanded.slug,
userId: feedExpanded.userId,
entityType: feedExpanded.entityType,
entityId: feedExpanded.entityId,
entityUpdatedAt: feedExpanded.entityUpdatedAt?.valueOf() || null,
coverPath: feedExpanded.coverPath || null,
meta: {
title: feedExpanded.title,
description: feedExpanded.description,
author: feedExpanded.author,
imageUrl: feedExpanded.imageURL,
feedUrl: feedExpanded.feedURL,
link: feedExpanded.siteURL,
explicit: feedExpanded.explicit,
type: feedExpanded.podcastType,
language: feedExpanded.language,
preventIndexing: feedExpanded.preventIndexing,
ownerName: feedExpanded.ownerName,
ownerEmail: feedExpanded.ownerEmail
},
serverAddress: feedExpanded.serverAddress,
feedUrl: feedExpanded.feedURL,
episodes,
createdAt: feedExpanded.createdAt.valueOf(),
updatedAt: feedExpanded.updatedAt.valueOf()
})
}
/**
* @param {string} feedId
* @returns {Promise<boolean>} - true if feed was removed
@ -142,23 +87,6 @@ class Feed extends Model {
)
}
/**
* Find feed where and return oldFeed
* @param {Object} where sequelize where object
* @returns {Promise<oldFeed>} oldFeed
*/
static async findOneOld(where) {
if (!where) return null
const feedExpanded = await this.findOne({
where,
include: {
model: this.sequelize.models.feedEpisode
}
})
if (!feedExpanded) return null
return this.getOldFeed(feedExpanded)
}
/**
*
* @param {string} userId
@ -663,6 +591,17 @@ class Feed extends Model {
return rssfeed.xml()
}
/**
*
* @param {string} id
* @returns {string}
*/
getEpisodePath(id) {
const episode = this.feedEpisodes.find((ep) => ep.id === id)
if (!episode) return null
return episode.filePath
}
toOldJSON() {
const episodes = this.feedEpisodes?.map((feedEpisode) => feedEpisode.getOldEpisode())
return {

View File

@ -55,12 +55,14 @@ class FeedEpisode extends Model {
* @param {import('./PodcastEpisode')} episode
*/
static getFeedEpisodeObjFromPodcastEpisode(libraryItemExpanded, feed, slug, episode) {
const episodeId = uuidv4()
return {
id: episodeId,
title: episode.title,
author: feed.author,
description: episode.description,
siteURL: feed.siteURL,
enclosureURL: `/feed/${slug}/item/${episode.id}/media${Path.extname(episode.audioFile.metadata.filename)}`,
enclosureURL: `/feed/${slug}/item/${episodeId}/media${Path.extname(episode.audioFile.metadata.filename)}`,
enclosureType: episode.audioFile.mimeType,
enclosureSize: episode.audioFile.metadata.size,
pubDate: episode.pubDate,

View File

@ -568,7 +568,7 @@ class LibraryItem extends Model {
oldLibraryItem.media.metadata.series = li.series
}
if (li.rssFeed) {
oldLibraryItem.rssFeed = this.sequelize.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.media.numEpisodes) {
oldLibraryItem.media.numEpisodes = li.media.numEpisodes

View File

@ -84,13 +84,6 @@ class Playlist extends Model {
const playlistExpanded = oldPlaylist.toJSONExpanded(libraryItems)
if (include?.includes('rssfeed')) {
const feeds = await this.getFeeds()
if (feeds?.length) {
playlistExpanded.rssFeed = this.sequelize.models.feed.getOldFeed(feeds[0])
}
}
return playlistExpanded
}

View File

@ -1,77 +0,0 @@
const FeedMeta = require('./FeedMeta')
const FeedEpisode = require('./FeedEpisode')
class Feed {
constructor(feed) {
this.id = null
this.slug = null
this.userId = null
this.entityType = null
this.entityId = null
this.entityUpdatedAt = null
this.coverPath = null
this.serverAddress = null
this.feedUrl = null
this.meta = null
this.episodes = null
this.createdAt = null
this.updatedAt = null
if (feed) {
this.construct(feed)
}
}
construct(feed) {
this.id = feed.id
this.slug = feed.slug
this.userId = feed.userId
this.entityType = feed.entityType
this.entityId = feed.entityId
this.entityUpdatedAt = feed.entityUpdatedAt
this.coverPath = feed.coverPath
this.serverAddress = feed.serverAddress
this.feedUrl = feed.feedUrl
this.meta = new FeedMeta(feed.meta)
this.episodes = feed.episodes.map((ep) => new FeedEpisode(ep))
this.createdAt = feed.createdAt
this.updatedAt = feed.updatedAt
}
toJSON() {
return {
id: this.id,
slug: this.slug,
userId: this.userId,
entityType: this.entityType,
entityId: this.entityId,
coverPath: this.coverPath,
serverAddress: this.serverAddress,
feedUrl: this.feedUrl,
meta: this.meta.toJSON(),
episodes: this.episodes.map((ep) => ep.toJSON()),
createdAt: this.createdAt,
updatedAt: this.updatedAt
}
}
toJSONMinified() {
return {
id: this.id,
entityType: this.entityType,
entityId: this.entityId,
feedUrl: this.feedUrl,
meta: this.meta.toJSONMinified()
}
}
getEpisodePath(id) {
var episode = this.episodes.find((ep) => ep.id === id)
if (!episode) return null
return episode.fullPath
}
}
module.exports = Feed

View File

@ -1,67 +0,0 @@
class FeedEpisode {
constructor(episode) {
this.id = null
this.title = null
this.description = null
this.enclosure = null
this.pubDate = null
this.link = null
this.author = null
this.explicit = null
this.duration = null
this.season = null
this.episode = null
this.episodeType = null
this.libraryItemId = null
this.episodeId = null
this.trackIndex = null
this.fullPath = null
if (episode) {
this.construct(episode)
}
}
construct(episode) {
this.id = episode.id
this.title = episode.title
this.description = episode.description
this.enclosure = episode.enclosure ? { ...episode.enclosure } : null
this.pubDate = episode.pubDate
this.link = episode.link
this.author = episode.author
this.explicit = episode.explicit
this.duration = episode.duration
this.season = episode.season
this.episode = episode.episode
this.episodeType = episode.episodeType
this.libraryItemId = episode.libraryItemId
this.episodeId = episode.episodeId || null
this.trackIndex = episode.trackIndex || 0
this.fullPath = episode.fullPath
}
toJSON() {
return {
id: this.id,
title: this.title,
description: this.description,
enclosure: this.enclosure ? { ...this.enclosure } : null,
pubDate: this.pubDate,
link: this.link,
author: this.author,
explicit: this.explicit,
duration: this.duration,
season: this.season,
episode: this.episode,
episodeType: this.episodeType,
libraryItemId: this.libraryItemId,
episodeId: this.episodeId,
trackIndex: this.trackIndex,
fullPath: this.fullPath
}
}
}
module.exports = FeedEpisode

View File

@ -1,63 +0,0 @@
class FeedMeta {
constructor(meta) {
this.title = null
this.description = null
this.author = null
this.imageUrl = null
this.feedUrl = null
this.link = null
this.explicit = null
this.type = null
this.language = null
this.preventIndexing = null
this.ownerName = null
this.ownerEmail = null
if (meta) {
this.construct(meta)
}
}
construct(meta) {
this.title = meta.title
this.description = meta.description
this.author = meta.author
this.imageUrl = meta.imageUrl
this.feedUrl = meta.feedUrl
this.link = meta.link
this.explicit = meta.explicit
this.type = meta.type
this.language = meta.language
this.preventIndexing = meta.preventIndexing
this.ownerName = meta.ownerName
this.ownerEmail = meta.ownerEmail
}
toJSON() {
return {
title: this.title,
description: this.description,
author: this.author,
imageUrl: this.imageUrl,
feedUrl: this.feedUrl,
link: this.link,
explicit: this.explicit,
type: this.type,
language: this.language,
preventIndexing: this.preventIndexing,
ownerName: this.ownerName,
ownerEmail: this.ownerEmail
}
}
toJSONMinified() {
return {
title: this.title,
description: this.description,
preventIndexing: this.preventIndexing,
ownerName: this.ownerName,
ownerEmail: this.ownerEmail
}
}
}
module.exports = FeedMeta

View File

@ -54,7 +54,7 @@ module.exports = {
items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.mediaItemShare) {
oldLibraryItem.mediaItemShare = li.mediaItemShare
@ -91,7 +91,7 @@ module.exports = {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.size && !oldLibraryItem.media.size) {
oldLibraryItem.media.size = li.size
@ -109,7 +109,7 @@ module.exports = {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.size && !oldLibraryItem.media.size) {
oldLibraryItem.media.size = li.size
@ -138,7 +138,7 @@ module.exports = {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.series) {
oldLibraryItem.media.metadata.series = li.series
@ -168,7 +168,7 @@ module.exports = {
items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.mediaItemShare) {
oldLibraryItem.mediaItemShare = li.mediaItemShare
@ -279,7 +279,7 @@ module.exports = {
const oldSeries = s.toOldJSON()
if (s.feeds?.length) {
oldSeries.rssFeed = Database.feedModel.getOldFeed(s.feeds[0]).toJSONMinified()
oldSeries.rssFeed = s.feeds[0].toOldJSONMinified()
}
// TODO: Sort books by sequence in query
@ -375,7 +375,7 @@ module.exports = {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.mediaItemShare) {
oldLibraryItem.mediaItemShare = li.mediaItemShare

View File

@ -615,8 +615,8 @@ module.exports = {
}
}
if (libraryItem.feeds?.length) {
libraryItem.rssFeed = libraryItem.feeds[0]
if (bookExpanded.libraryItem.feeds?.length) {
libraryItem.rssFeed = bookExpanded.libraryItem.feeds[0]
}
if (includeMediaItemShare) {
@ -766,8 +766,8 @@ module.exports = {
name: s.name,
sequence: s.bookSeries[bookIndex].sequence
}
if (libraryItem.feeds?.length) {
libraryItem.rssFeed = libraryItem.feeds[0]
if (s.bookSeries[bookIndex].book.libraryItem.feeds?.length) {
libraryItem.rssFeed = s.bookSeries[bookIndex].book.libraryItem.feeds[0]
}
libraryItem.media = book
return libraryItem
@ -900,8 +900,8 @@ module.exports = {
delete book.libraryItem
libraryItem.media = book
if (libraryItem.feeds?.length) {
libraryItem.rssFeed = libraryItem.feeds[0]
if (bookExpanded.libraryItem.feeds?.length) {
libraryItem.rssFeed = bookExpanded.libraryItem.feeds[0]
}
return libraryItem

View File

@ -180,8 +180,8 @@ module.exports = {
delete podcast.libraryItem
if (libraryItem.feeds?.length) {
libraryItem.rssFeed = libraryItem.feeds[0]
if (podcastExpanded.libraryItem.feeds?.length) {
libraryItem.rssFeed = podcastExpanded.libraryItem.feeds[0]
}
if (podcast.numEpisodesIncomplete) {
libraryItem.numEpisodesIncomplete = podcast.numEpisodesIncomplete

View File

@ -182,7 +182,7 @@ module.exports = {
}
if (s.feeds?.length) {
oldSeries.rssFeed = Database.feedModel.getOldFeed(s.feeds[0]).toJSONMinified()
oldSeries.rssFeed = s.feeds[0].toOldJSONMinified()
}
// TODO: Sort books by sequence in query