mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-12-20 18:59:37 +00:00
Merge remote-tracking branch 'origin/master' into auth_passportjs
This commit is contained in:
commit
be53b31712
100 changed files with 2799 additions and 1217 deletions
|
|
@ -70,17 +70,19 @@ class Feed {
|
|||
id: this.id,
|
||||
entityType: this.entityType,
|
||||
entityId: this.entityId,
|
||||
feedUrl: this.feedUrl
|
||||
feedUrl: this.feedUrl,
|
||||
meta: this.meta.toJSONMinified(),
|
||||
}
|
||||
}
|
||||
|
||||
getEpisodePath(id) {
|
||||
var episode = this.episodes.find(ep => ep.id === id)
|
||||
console.log('getEpisodePath=', id, episode)
|
||||
if (!episode) return null
|
||||
return episode.fullPath
|
||||
}
|
||||
|
||||
setFromItem(userId, slug, libraryItem, serverAddress) {
|
||||
setFromItem(userId, slug, libraryItem, serverAddress, preventIndexing = true, ownerName = null, ownerEmail = null) {
|
||||
const media = libraryItem.media
|
||||
const mediaMetadata = media.metadata
|
||||
const isPodcast = libraryItem.mediaType === 'podcast'
|
||||
|
|
@ -106,6 +108,11 @@ class Feed {
|
|||
this.meta.feedUrl = feedUrl
|
||||
this.meta.link = `${serverAddress}/item/${libraryItem.id}`
|
||||
this.meta.explicit = !!mediaMetadata.explicit
|
||||
this.meta.type = mediaMetadata.type
|
||||
this.meta.language = mediaMetadata.language
|
||||
this.meta.preventIndexing = preventIndexing
|
||||
this.meta.ownerName = ownerName
|
||||
this.meta.ownerEmail = ownerEmail
|
||||
|
||||
this.episodes = []
|
||||
if (isPodcast) { // PODCAST EPISODES
|
||||
|
|
@ -142,6 +149,8 @@ class Feed {
|
|||
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.meta.type = mediaMetadata.type
|
||||
this.meta.language = mediaMetadata.language
|
||||
|
||||
this.episodes = []
|
||||
if (isPodcast) { // PODCAST EPISODES
|
||||
|
|
@ -333,4 +342,4 @@ class Feed {
|
|||
return author
|
||||
}
|
||||
}
|
||||
module.exports = Feed
|
||||
module.exports = Feed
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ class FeedEpisode {
|
|||
this.author = null
|
||||
this.explicit = null
|
||||
this.duration = null
|
||||
this.season = null
|
||||
this.episode = null
|
||||
this.episodeType = null
|
||||
|
||||
this.libraryItemId = null
|
||||
this.episodeId = null
|
||||
|
|
@ -35,6 +38,9 @@ class FeedEpisode {
|
|||
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
|
||||
|
|
@ -52,6 +58,9 @@ class FeedEpisode {
|
|||
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,
|
||||
|
|
@ -77,25 +86,31 @@ class FeedEpisode {
|
|||
this.author = meta.author
|
||||
this.explicit = mediaMetadata.explicit
|
||||
this.duration = episode.duration
|
||||
this.season = episode.season
|
||||
this.episode = episode.episode
|
||||
this.episodeType = episode.episodeType
|
||||
this.libraryItemId = libraryItem.id
|
||||
this.episodeId = episode.id
|
||||
this.trackIndex = 0
|
||||
this.fullPath = episode.audioFile.metadata.path
|
||||
}
|
||||
|
||||
setFromAudiobookTrack(libraryItem, serverAddress, slug, audioTrack, meta, additionalOffset = 0) {
|
||||
setFromAudiobookTrack(libraryItem, serverAddress, slug, audioTrack, meta, additionalOffset = null) {
|
||||
// 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 = String(audioTrack.index)
|
||||
|
||||
// Additional offset can be used for collections/series
|
||||
if (additionalOffset && !isNaN(additionalOffset)) {
|
||||
if (additionalOffset !== null && !isNaN(additionalOffset)) {
|
||||
timeOffset += Number(additionalOffset) * 1000
|
||||
|
||||
episodeId = String(additionalOffset) + '-' + episodeId
|
||||
}
|
||||
|
||||
// e.g. Track 1 will have a pub date before Track 2
|
||||
const audiobookPubDate = date.format(new Date(libraryItem.addedAt + timeOffset), 'ddd, DD MMM YYYY HH:mm:ss [GMT]')
|
||||
|
||||
const contentUrl = `/feed/${slug}/item/${audioTrack.index}/${audioTrack.metadata.filename}`
|
||||
const contentUrl = `/feed/${slug}/item/${episodeId}/${audioTrack.metadata.filename}`
|
||||
const media = libraryItem.media
|
||||
const mediaMetadata = media.metadata
|
||||
|
||||
|
|
@ -110,7 +125,7 @@ class FeedEpisode {
|
|||
}
|
||||
}
|
||||
|
||||
this.id = String(audioTrack.index)
|
||||
this.id = episodeId
|
||||
this.title = title
|
||||
this.description = mediaMetadata.description || ''
|
||||
this.enclosure = {
|
||||
|
|
@ -144,9 +159,12 @@ class FeedEpisode {
|
|||
{ 'itunes:summary': this.description || '' },
|
||||
{
|
||||
"itunes:explicit": !!this.explicit
|
||||
}
|
||||
},
|
||||
{ "itunes:episodeType": this.episodeType },
|
||||
{ "itunes:season": this.season },
|
||||
{ "itunes:episode": this.episode }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = FeedEpisode
|
||||
module.exports = FeedEpisode
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ class FeedMeta {
|
|||
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)
|
||||
|
|
@ -21,6 +26,11 @@ class FeedMeta {
|
|||
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() {
|
||||
|
|
@ -31,7 +41,22 @@ class FeedMeta {
|
|||
imageUrl: this.imageUrl,
|
||||
feedUrl: this.feedUrl,
|
||||
link: this.link,
|
||||
explicit: this.explicit
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,16 +68,18 @@ class FeedMeta {
|
|||
feed_url: this.feedUrl,
|
||||
site_url: this.link,
|
||||
image_url: this.imageUrl,
|
||||
language: 'en',
|
||||
custom_namespaces: {
|
||||
'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
'psc': 'http://podlove.org/simple-chapters',
|
||||
'podcast': 'https://podcastindex.org/namespace/1.0'
|
||||
'podcast': 'https://podcastindex.org/namespace/1.0',
|
||||
'googleplay': 'http://www.google.com/schemas/play-podcasts/1.0'
|
||||
},
|
||||
custom_elements: [
|
||||
{ 'language': this.language || 'en' },
|
||||
{ 'author': this.author || 'advplyr' },
|
||||
{ 'itunes:author': this.author || 'advplyr' },
|
||||
{ 'itunes:summary': this.description || '' },
|
||||
{ 'itunes:type': this.type },
|
||||
{
|
||||
'itunes:image': {
|
||||
_attr: {
|
||||
|
|
@ -62,15 +89,15 @@ class FeedMeta {
|
|||
},
|
||||
{
|
||||
'itunes:owner': [
|
||||
{ 'itunes:name': this.author || '' },
|
||||
{ 'itunes:email': '' }
|
||||
{ 'itunes:name': this.ownerName || this.author || '' },
|
||||
{ 'itunes:email': this.ownerEmail || '' }
|
||||
]
|
||||
},
|
||||
{
|
||||
"itunes:explicit": !!this.explicit
|
||||
}
|
||||
{ 'itunes:explicit': !!this.explicit },
|
||||
{ 'itunes:block': this.preventIndexing?"Yes":"No" },
|
||||
{ 'googleplay:block': this.preventIndexing?"yes":"no" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = FeedMeta
|
||||
module.exports = FeedMeta
|
||||
|
|
|
|||
|
|
@ -197,9 +197,15 @@ class LibraryItem {
|
|||
if (key === 'libraryFiles') {
|
||||
this.libraryFiles = payload.libraryFiles.map(lf => lf.clone())
|
||||
|
||||
// Use first image library file as cover
|
||||
const firstImageFile = this.libraryFiles.find(lf => lf.fileType === 'image')
|
||||
if (firstImageFile) this.media.coverPath = firstImageFile.metadata.path
|
||||
// Set cover image
|
||||
const imageFiles = this.libraryFiles.filter(lf => lf.fileType === 'image')
|
||||
const coverMatch = imageFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
||||
if (coverMatch) {
|
||||
this.media.coverPath = coverMatch.metadata.path
|
||||
} else if (imageFiles.length) {
|
||||
this.media.coverPath = imageFiles[0].metadata.path
|
||||
}
|
||||
|
||||
} else if (this[key] !== undefined && key !== 'media') {
|
||||
this[key] = payload[key]
|
||||
}
|
||||
|
|
@ -330,6 +336,7 @@ class LibraryItem {
|
|||
}
|
||||
|
||||
if (dataFound.ino !== this.ino) {
|
||||
Logger.warn(`[LibraryItem] Check scan item changed inode "${this.ino}" -> "${dataFound.ino}"`)
|
||||
this.ino = dataFound.ino
|
||||
hasUpdated = true
|
||||
}
|
||||
|
|
@ -341,7 +348,7 @@ class LibraryItem {
|
|||
}
|
||||
|
||||
if (dataFound.path !== this.path) {
|
||||
Logger.warn(`[LibraryItem] Check scan item changed path "${this.path}" -> "${dataFound.path}"`)
|
||||
Logger.warn(`[LibraryItem] Check scan item changed path "${this.path}" -> "${dataFound.path}" (inode ${this.ino})`)
|
||||
this.path = dataFound.path
|
||||
this.relPath = dataFound.relPath
|
||||
hasUpdated = true
|
||||
|
|
@ -444,8 +451,14 @@ class LibraryItem {
|
|||
// Set cover image if not set
|
||||
const imageFiles = this.libraryFiles.filter(lf => lf.fileType === 'image')
|
||||
if (imageFiles.length && !this.media.coverPath) {
|
||||
this.media.coverPath = imageFiles[0].metadata.path
|
||||
Logger.debug('[LibraryItem] Set media cover path', this.media.coverPath)
|
||||
// attempt to find a file called cover.<ext> otherwise just fall back to the first image found
|
||||
const coverMatch = imageFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
||||
if (coverMatch) {
|
||||
this.media.coverPath = coverMatch.metadata.path
|
||||
} else {
|
||||
this.media.coverPath = imageFiles[0].metadata.path
|
||||
}
|
||||
Logger.info('[LibraryItem] Set media cover path', this.media.coverPath)
|
||||
hasUpdated = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const Path = require('path')
|
||||
const { getId } = require('../utils/index')
|
||||
const { sanitizeFilename } = require('../utils/fileUtils')
|
||||
const globals = require('../utils/globals')
|
||||
|
||||
class PodcastEpisodeDownload {
|
||||
constructor() {
|
||||
|
|
@ -8,9 +9,9 @@ class PodcastEpisodeDownload {
|
|||
this.podcastEpisode = null
|
||||
this.url = null
|
||||
this.libraryItem = null
|
||||
this.libraryId = null
|
||||
|
||||
this.isAutoDownload = false
|
||||
this.isDownloading = false
|
||||
this.isFinished = false
|
||||
this.failed = false
|
||||
|
||||
|
|
@ -22,20 +23,32 @@ class PodcastEpisodeDownload {
|
|||
toJSONForClient() {
|
||||
return {
|
||||
id: this.id,
|
||||
episodeDisplayTitle: this.podcastEpisode ? this.podcastEpisode.title : null,
|
||||
episodeDisplayTitle: this.podcastEpisode?.title ?? null,
|
||||
url: this.url,
|
||||
libraryItemId: this.libraryItem ? this.libraryItem.id : null,
|
||||
isDownloading: this.isDownloading,
|
||||
libraryItemId: this.libraryItem?.id || null,
|
||||
libraryId: this.libraryId || null,
|
||||
isFinished: this.isFinished,
|
||||
failed: this.failed,
|
||||
startedAt: this.startedAt,
|
||||
createdAt: this.createdAt,
|
||||
finishedAt: this.finishedAt
|
||||
finishedAt: this.finishedAt,
|
||||
podcastTitle: this.libraryItem?.media.metadata.title ?? null,
|
||||
podcastExplicit: !!this.libraryItem?.media.metadata.explicit,
|
||||
season: this.podcastEpisode?.season ?? null,
|
||||
episode: this.podcastEpisode?.episode ?? null,
|
||||
episodeType: this.podcastEpisode?.episodeType ?? 'full',
|
||||
publishedAt: this.podcastEpisode?.publishedAt ?? null
|
||||
}
|
||||
}
|
||||
|
||||
get fileExtension() {
|
||||
const extname = Path.extname(this.url).substring(1).toLowerCase()
|
||||
if (globals.SupportedAudioTypes.includes(extname)) return extname
|
||||
return 'mp3'
|
||||
}
|
||||
|
||||
get targetFilename() {
|
||||
return sanitizeFilename(`${this.podcastEpisode.title}.mp3`)
|
||||
return sanitizeFilename(`${this.podcastEpisode.title}.${this.fileExtension}`)
|
||||
}
|
||||
get targetPath() {
|
||||
return Path.join(this.libraryItem.path, this.targetFilename)
|
||||
|
|
@ -47,13 +60,21 @@ class PodcastEpisodeDownload {
|
|||
return this.libraryItem ? this.libraryItem.id : null
|
||||
}
|
||||
|
||||
setData(podcastEpisode, libraryItem, isAutoDownload) {
|
||||
setData(podcastEpisode, libraryItem, isAutoDownload, libraryId) {
|
||||
this.id = getId('epdl')
|
||||
this.podcastEpisode = podcastEpisode
|
||||
this.url = podcastEpisode.enclosure.url
|
||||
|
||||
const url = podcastEpisode.enclosure.url
|
||||
if (decodeURIComponent(url) !== url) { // Already encoded
|
||||
this.url = url
|
||||
} else {
|
||||
this.url = encodeURI(url)
|
||||
}
|
||||
|
||||
this.libraryItem = libraryItem
|
||||
this.isAutoDownload = isAutoDownload
|
||||
this.createdAt = Date.now()
|
||||
this.libraryId = libraryId
|
||||
}
|
||||
|
||||
setFinished(success) {
|
||||
|
|
@ -62,4 +83,4 @@ class PodcastEpisodeDownload {
|
|||
this.failed = !success
|
||||
}
|
||||
}
|
||||
module.exports = PodcastEpisodeDownload
|
||||
module.exports = PodcastEpisodeDownload
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ class Stream extends EventEmitter {
|
|||
AudioMimeType.WMA,
|
||||
AudioMimeType.AIFF,
|
||||
AudioMimeType.WEBM,
|
||||
AudioMimeType.WEBMA
|
||||
AudioMimeType.WEBMA,
|
||||
AudioMimeType.AWB
|
||||
]
|
||||
}
|
||||
get codecsToForceAAC() {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class PodcastEpisode {
|
|||
this.enclosure = data.enclosure ? { ...data.enclosure } : null
|
||||
this.season = data.season || ''
|
||||
this.episode = data.episode || ''
|
||||
this.episodeType = data.episodeType || ''
|
||||
this.episodeType = data.episodeType || 'full'
|
||||
this.publishedAt = data.publishedAt || 0
|
||||
this.addedAt = Date.now()
|
||||
this.updatedAt = Date.now()
|
||||
|
|
@ -165,4 +165,4 @@ class PodcastEpisode {
|
|||
return cleanStringForSearch(this.title).includes(query)
|
||||
}
|
||||
}
|
||||
module.exports = PodcastEpisode
|
||||
module.exports = PodcastEpisode
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ class Book {
|
|||
})
|
||||
}
|
||||
} else if (key === 'narrators') {
|
||||
if (opfMetadata.narrators && opfMetadata.narrators.length && (!this.metadata.narrators.length || opfMetadataOverrideDetails)) {
|
||||
if (opfMetadata.narrators?.length && (!this.metadata.narrators.length || opfMetadataOverrideDetails)) {
|
||||
metadataUpdatePayload.narrators = opfMetadata.narrators
|
||||
}
|
||||
} else if (key === 'series') {
|
||||
|
|
@ -356,9 +356,9 @@ class Book {
|
|||
}
|
||||
|
||||
updateAudioTracks(orderedFileData) {
|
||||
var index = 1
|
||||
let index = 1
|
||||
this.audioFiles = orderedFileData.map((fileData) => {
|
||||
var audioFile = this.audioFiles.find(af => af.ino === fileData.ino)
|
||||
const audioFile = this.audioFiles.find(af => af.ino === fileData.ino)
|
||||
audioFile.manuallyVerified = true
|
||||
audioFile.invalid = false
|
||||
audioFile.error = null
|
||||
|
|
@ -376,11 +376,11 @@ class Book {
|
|||
this.rebuildTracks()
|
||||
}
|
||||
|
||||
rebuildTracks(preferOverdriveMediaMarker) {
|
||||
rebuildTracks() {
|
||||
Logger.debug(`[Book] Tracks being rebuilt...!`)
|
||||
this.audioFiles.sort((a, b) => a.index - b.index)
|
||||
this.missingParts = []
|
||||
this.setChapters(preferOverdriveMediaMarker)
|
||||
this.setChapters()
|
||||
this.checkUpdateMissingTracks()
|
||||
}
|
||||
|
||||
|
|
@ -412,14 +412,16 @@ class Book {
|
|||
return wasUpdated
|
||||
}
|
||||
|
||||
setChapters(preferOverdriveMediaMarker = false) {
|
||||
setChapters() {
|
||||
const preferOverdriveMediaMarker = !!global.ServerSettings.scannerPreferOverdriveMediaMarker
|
||||
|
||||
// If 1 audio file without chapters, then no chapters will be set
|
||||
var includedAudioFiles = this.audioFiles.filter(af => !af.exclude)
|
||||
const includedAudioFiles = this.audioFiles.filter(af => !af.exclude)
|
||||
if (!includedAudioFiles.length) return
|
||||
|
||||
// If overdrive media markers are present and preferred, use those instead
|
||||
if (preferOverdriveMediaMarker) {
|
||||
var overdriveChapters = parseOverdriveMediaMarkersAsChapters(includedAudioFiles)
|
||||
const overdriveChapters = parseOverdriveMediaMarkersAsChapters(includedAudioFiles)
|
||||
if (overdriveChapters) {
|
||||
Logger.info('[Book] Overdrive Media Markers and preference found! Using these for chapter definitions')
|
||||
this.chapters = overdriveChapters
|
||||
|
|
@ -460,17 +462,26 @@ class Book {
|
|||
})
|
||||
}
|
||||
} else if (includedAudioFiles.length > 1) {
|
||||
const preferAudioMetadata = !!global.ServerSettings.scannerPreferAudioMetadata
|
||||
|
||||
// Build chapters from audio files
|
||||
this.chapters = []
|
||||
var currChapterId = 0
|
||||
var currStartTime = 0
|
||||
let currChapterId = 0
|
||||
let currStartTime = 0
|
||||
includedAudioFiles.forEach((file) => {
|
||||
if (file.duration) {
|
||||
let title = file.metadata.filename ? Path.basename(file.metadata.filename, Path.extname(file.metadata.filename)) : `Chapter ${currChapterId}`
|
||||
|
||||
// When prefer audio metadata server setting is set then use ID3 title tag as long as it is not the same as the book title
|
||||
if (preferAudioMetadata && file.metaTags?.tagTitle && file.metaTags?.tagTitle !== this.metadata.title) {
|
||||
title = file.metaTags.tagTitle
|
||||
}
|
||||
|
||||
this.chapters.push({
|
||||
id: currChapterId++,
|
||||
start: currStartTime,
|
||||
end: currStartTime + file.duration,
|
||||
title: file.metadata.filename ? Path.basename(file.metadata.filename, Path.extname(file.metadata.filename)) : `Chapter ${currChapterId}`
|
||||
title
|
||||
})
|
||||
currStartTime += file.duration
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class BookMetadata {
|
|||
this.asin = null
|
||||
this.language = null
|
||||
this.explicit = false
|
||||
this.abridged = false
|
||||
|
||||
if (metadata) {
|
||||
this.construct(metadata)
|
||||
|
|
@ -38,6 +39,7 @@ class BookMetadata {
|
|||
this.asin = metadata.asin
|
||||
this.language = metadata.language
|
||||
this.explicit = !!metadata.explicit
|
||||
this.abridged = !!metadata.abridged
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
|
@ -55,7 +57,8 @@ class BookMetadata {
|
|||
isbn: this.isbn,
|
||||
asin: this.asin,
|
||||
language: this.language,
|
||||
explicit: this.explicit
|
||||
explicit: this.explicit,
|
||||
abridged: this.abridged
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +79,8 @@ class BookMetadata {
|
|||
isbn: this.isbn,
|
||||
asin: this.asin,
|
||||
language: this.language,
|
||||
explicit: this.explicit
|
||||
explicit: this.explicit,
|
||||
abridged: this.abridged
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +104,8 @@ class BookMetadata {
|
|||
authorName: this.authorName,
|
||||
authorNameLF: this.authorNameLF,
|
||||
narratorName: this.narratorName,
|
||||
seriesName: this.seriesName
|
||||
seriesName: this.seriesName,
|
||||
abridged: this.abridged
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class PodcastMetadata {
|
|||
this.itunesArtistId = null
|
||||
this.explicit = false
|
||||
this.language = null
|
||||
this.type = null
|
||||
|
||||
if (metadata) {
|
||||
this.construct(metadata)
|
||||
|
|
@ -34,6 +35,7 @@ class PodcastMetadata {
|
|||
this.itunesArtistId = metadata.itunesArtistId
|
||||
this.explicit = metadata.explicit
|
||||
this.language = metadata.language || null
|
||||
this.type = metadata.type || 'episodic'
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
|
@ -49,7 +51,8 @@ class PodcastMetadata {
|
|||
itunesId: this.itunesId,
|
||||
itunesArtistId: this.itunesArtistId,
|
||||
explicit: this.explicit,
|
||||
language: this.language
|
||||
language: this.language,
|
||||
type: this.type
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +70,8 @@ class PodcastMetadata {
|
|||
itunesId: this.itunesId,
|
||||
itunesArtistId: this.itunesArtistId,
|
||||
explicit: this.explicit,
|
||||
language: this.language
|
||||
language: this.language,
|
||||
type: this.type
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +116,7 @@ class PodcastMetadata {
|
|||
this.itunesArtistId = mediaMetadata.itunesArtistId || null
|
||||
this.explicit = !!mediaMetadata.explicit
|
||||
this.language = mediaMetadata.language || null
|
||||
this.type = mediaMetadata.type || null
|
||||
if (mediaMetadata.genres && mediaMetadata.genres.length) {
|
||||
this.genres = [...mediaMetadata.genres]
|
||||
}
|
||||
|
|
@ -132,4 +137,4 @@ class PodcastMetadata {
|
|||
return hasUpdates
|
||||
}
|
||||
}
|
||||
module.exports = PodcastMetadata
|
||||
module.exports = PodcastMetadata
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class ServerSettings {
|
|||
this.chromecastEnabled = false
|
||||
this.enableEReader = false
|
||||
this.dateFormat = 'MM/dd/yyyy'
|
||||
this.timeFormat = 'HH:mm'
|
||||
this.language = 'en-us'
|
||||
|
||||
this.logLevel = Logger.logLevel
|
||||
|
|
@ -106,6 +107,7 @@ class ServerSettings {
|
|||
this.chromecastEnabled = !!settings.chromecastEnabled
|
||||
this.enableEReader = !!settings.enableEReader
|
||||
this.dateFormat = settings.dateFormat || 'MM/dd/yyyy'
|
||||
this.timeFormat = settings.timeFormat || 'HH:mm'
|
||||
this.language = settings.language || 'en-us'
|
||||
this.logLevel = settings.logLevel || Logger.logLevel
|
||||
this.version = settings.version || null
|
||||
|
|
@ -180,6 +182,7 @@ class ServerSettings {
|
|||
chromecastEnabled: this.chromecastEnabled,
|
||||
enableEReader: this.enableEReader,
|
||||
dateFormat: this.dateFormat,
|
||||
timeFormat: this.timeFormat,
|
||||
language: this.language,
|
||||
logLevel: this.logLevel,
|
||||
version: this.version,
|
||||
|
|
@ -218,4 +221,4 @@ class ServerSettings {
|
|||
return hasUpdates
|
||||
}
|
||||
}
|
||||
module.exports = ServerSettings
|
||||
module.exports = ServerSettings
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue