mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-19 03:15:58 +02:00
Refactor Feed model to create new feed for collection
This commit is contained in:
@@ -132,12 +132,12 @@ class FeedEpisode extends Model {
|
||||
/**
|
||||
* If chapters for an audiobook match the audio tracks then use chapter titles instead of audio file names
|
||||
*
|
||||
* @param {import('./LibraryItem').LibraryItemExpanded} libraryItemExpanded
|
||||
* @param {import('./Book')} book
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static checkUseChapterTitlesForEpisodes(libraryItemExpanded) {
|
||||
const tracks = libraryItemExpanded.media.trackList || []
|
||||
const chapters = libraryItemExpanded.media.chapters || []
|
||||
static checkUseChapterTitlesForEpisodes(book) {
|
||||
const tracks = book.trackList || []
|
||||
const chapters = book.chapters || []
|
||||
if (tracks.length !== chapters.length) return false
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
if (Math.abs(chapters[i].start - tracks[i].startOffset) >= 1) {
|
||||
@@ -149,32 +149,31 @@ class FeedEpisode extends Model {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./LibraryItem').LibraryItemExpanded} libraryItemExpanded
|
||||
* @param {import('./Book')} book
|
||||
* @param {Date} pubDateStart
|
||||
* @param {import('./Feed')} feed
|
||||
* @param {string} slug
|
||||
* @param {import('./Book').AudioFileObject} audioTrack
|
||||
* @param {boolean} useChapterTitles
|
||||
* @param {string} [pubDateOverride]
|
||||
*/
|
||||
static getFeedEpisodeObjFromAudiobookTrack(libraryItemExpanded, feed, slug, audioTrack, useChapterTitles, pubDateOverride = null) {
|
||||
static getFeedEpisodeObjFromAudiobookTrack(book, pubDateStart, feed, slug, audioTrack, useChapterTitles) {
|
||||
// Example: <pubDate>Fri, 04 Feb 2015 00:00:00 GMT</pubDate>
|
||||
let timeOffset = isNaN(audioTrack.index) ? 0 : Number(audioTrack.index) * 1000 // Offset pubdate to ensure correct order
|
||||
let episodeId = uuidv4()
|
||||
|
||||
// e.g. Track 1 will have a pub date before Track 2
|
||||
const audiobookPubDate = pubDateOverride || date.format(new Date(libraryItemExpanded.createdAt.valueOf() + timeOffset), 'ddd, DD MMM YYYY HH:mm:ss [GMT]')
|
||||
const audiobookPubDate = date.format(new Date(pubDateStart.valueOf() + timeOffset), 'ddd, DD MMM YYYY HH:mm:ss [GMT]')
|
||||
|
||||
const contentUrl = `/feed/${slug}/item/${episodeId}/media${Path.extname(audioTrack.metadata.filename)}`
|
||||
const media = libraryItemExpanded.media
|
||||
|
||||
let title = audioTrack.title
|
||||
if (media.trackList.length == 1) {
|
||||
if (book.trackList.length == 1) {
|
||||
// If audiobook is a single file, use book title instead of chapter/file title
|
||||
title = media.title
|
||||
title = book.title
|
||||
} else {
|
||||
if (useChapterTitles) {
|
||||
// If audio track start and chapter start are within 1 seconds of eachother then use the chapter title
|
||||
const matchingChapter = media.chapters.find((ch) => Math.abs(ch.start - audioTrack.startOffset) < 1)
|
||||
const matchingChapter = book.chapters.find((ch) => Math.abs(ch.start - audioTrack.startOffset) < 1)
|
||||
if (matchingChapter?.title) title = matchingChapter.title
|
||||
}
|
||||
}
|
||||
@@ -183,7 +182,7 @@ class FeedEpisode extends Model {
|
||||
id: episodeId,
|
||||
title,
|
||||
author: feed.author,
|
||||
description: media.description || '',
|
||||
description: book.description || '',
|
||||
siteURL: feed.siteURL,
|
||||
enclosureURL: contentUrl,
|
||||
enclosureType: audioTrack.mimeType,
|
||||
@@ -191,7 +190,7 @@ class FeedEpisode extends Model {
|
||||
pubDate: audiobookPubDate,
|
||||
duration: audioTrack.duration,
|
||||
filePath: audioTrack.metadata.path,
|
||||
explicit: media.explicit,
|
||||
explicit: book.explicit,
|
||||
feedId: feed.id
|
||||
}
|
||||
}
|
||||
@@ -205,11 +204,37 @@ class FeedEpisode extends Model {
|
||||
* @returns {Promise<FeedEpisode[]>}
|
||||
*/
|
||||
static async createFromAudiobookTracks(libraryItemExpanded, feed, slug, transaction) {
|
||||
const useChapterTitles = this.checkUseChapterTitlesForEpisodes(libraryItemExpanded)
|
||||
const useChapterTitles = this.checkUseChapterTitlesForEpisodes(libraryItemExpanded.media)
|
||||
|
||||
const feedEpisodeObjs = []
|
||||
for (const track of libraryItemExpanded.media.trackList) {
|
||||
feedEpisodeObjs.push(this.getFeedEpisodeObjFromAudiobookTrack(libraryItemExpanded, feed, slug, track, useChapterTitles))
|
||||
feedEpisodeObjs.push(this.getFeedEpisodeObjFromAudiobookTrack(libraryItemExpanded.media, libraryItemExpanded.createdAt, feed, slug, track, useChapterTitles))
|
||||
}
|
||||
Logger.info(`[FeedEpisode] Creating ${feedEpisodeObjs.length} episodes for feed ${feed.id}`)
|
||||
return this.bulkCreate(feedEpisodeObjs, { transaction })
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./Collection')} collectionExpanded
|
||||
* @param {import('./Feed')} feed
|
||||
* @param {string} slug
|
||||
* @param {import('sequelize').Transaction} transaction
|
||||
* @returns {Promise<FeedEpisode[]>}
|
||||
*/
|
||||
static async createFromCollectionBooks(collectionExpanded, feed, slug, transaction) {
|
||||
const booksWithTracks = collectionExpanded.books.filter((book) => book.includedAudioFiles.length)
|
||||
|
||||
const earliestLibraryItemCreatedAt = collectionExpanded.books.reduce((earliest, book) => {
|
||||
return book.libraryItem.createdAt < earliest.libraryItem.createdAt ? book : earliest
|
||||
}).libraryItem.createdAt
|
||||
|
||||
const feedEpisodeObjs = []
|
||||
for (const book of booksWithTracks) {
|
||||
const useChapterTitles = this.checkUseChapterTitlesForEpisodes(book)
|
||||
for (const track of book.trackList) {
|
||||
feedEpisodeObjs.push(this.getFeedEpisodeObjFromAudiobookTrack(book, earliestLibraryItemCreatedAt, feed, slug, track, useChapterTitles))
|
||||
}
|
||||
}
|
||||
Logger.info(`[FeedEpisode] Creating ${feedEpisodeObjs.length} episodes for feed ${feed.id}`)
|
||||
return this.bulkCreate(feedEpisodeObjs, { transaction })
|
||||
|
Reference in New Issue
Block a user