2022-03-22 01:24:38 +01:00
|
|
|
const Path = require('path')
|
2024-11-08 00:26:51 +01:00
|
|
|
const uuidv4 = require('uuid').v4
|
|
|
|
const { sanitizeFilename, filePathToPOSIX } = require('../utils/fileUtils')
|
2023-03-16 00:04:31 +01:00
|
|
|
const globals = require('../utils/globals')
|
2022-03-22 01:24:38 +01:00
|
|
|
|
|
|
|
class PodcastEpisodeDownload {
|
|
|
|
constructor() {
|
|
|
|
this.id = null
|
|
|
|
this.podcastEpisode = null
|
|
|
|
this.url = null
|
|
|
|
this.libraryItem = null
|
2023-02-27 03:56:07 +01:00
|
|
|
this.libraryId = null
|
2022-03-22 01:24:38 +01:00
|
|
|
|
2022-08-16 00:35:13 +02:00
|
|
|
this.isAutoDownload = false
|
2022-04-24 02:41:06 +02:00
|
|
|
this.isFinished = false
|
|
|
|
this.failed = false
|
|
|
|
|
2023-05-28 18:24:51 +02:00
|
|
|
this.appendEpisodeId = false
|
|
|
|
|
2022-03-22 01:24:38 +01:00
|
|
|
this.startedAt = null
|
|
|
|
this.createdAt = null
|
|
|
|
this.finishedAt = null
|
|
|
|
}
|
|
|
|
|
2022-04-24 02:41:06 +02:00
|
|
|
toJSONForClient() {
|
|
|
|
return {
|
|
|
|
id: this.id,
|
2023-03-05 17:35:34 +01:00
|
|
|
episodeDisplayTitle: this.podcastEpisode?.title ?? null,
|
2022-04-24 02:41:06 +02:00
|
|
|
url: this.url,
|
2023-03-05 17:35:34 +01:00
|
|
|
libraryItemId: this.libraryItem?.id || null,
|
2023-02-27 03:56:07 +01:00
|
|
|
libraryId: this.libraryId || null,
|
2022-04-24 02:41:06 +02:00
|
|
|
isFinished: this.isFinished,
|
|
|
|
failed: this.failed,
|
2023-05-28 18:24:51 +02:00
|
|
|
appendEpisodeId: this.appendEpisodeId,
|
2022-04-24 02:41:06 +02:00
|
|
|
startedAt: this.startedAt,
|
|
|
|
createdAt: this.createdAt,
|
2023-02-27 03:56:07 +01:00
|
|
|
finishedAt: this.finishedAt,
|
2023-03-05 17:35:34 +01:00
|
|
|
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
|
2022-04-24 02:41:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-01 23:31:04 +02:00
|
|
|
get urlFileExtension() {
|
|
|
|
const cleanUrl = this.url.split('?')[0] // Remove query string
|
|
|
|
return Path.extname(cleanUrl).substring(1).toLowerCase()
|
|
|
|
}
|
2023-03-16 00:04:31 +01:00
|
|
|
get fileExtension() {
|
2023-04-01 23:31:04 +02:00
|
|
|
const extname = this.urlFileExtension
|
2023-03-16 00:04:31 +01:00
|
|
|
if (globals.SupportedAudioTypes.includes(extname)) return extname
|
|
|
|
return 'mp3'
|
|
|
|
}
|
2024-12-13 23:06:00 +01:00
|
|
|
get enclosureType() {
|
|
|
|
const enclosureType = this.podcastEpisode?.enclosure?.type
|
|
|
|
return typeof enclosureType === 'string' ? enclosureType : null
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* RSS feed may have an episode with file extension of mp3 but the specified enclosure type is not mpeg.
|
|
|
|
* @see https://github.com/advplyr/audiobookshelf/issues/3711
|
|
|
|
*
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
get isMp3() {
|
|
|
|
if (this.enclosureType && !this.enclosureType.includes('mpeg')) return false
|
|
|
|
return this.fileExtension === 'mp3'
|
|
|
|
}
|
2023-03-16 00:04:31 +01:00
|
|
|
|
2022-03-22 01:24:38 +01:00
|
|
|
get targetFilename() {
|
2023-05-28 18:24:51 +02:00
|
|
|
const appendage = this.appendEpisodeId ? ` (${this.podcastEpisode.id})` : ''
|
|
|
|
const filename = `${this.podcastEpisode.title}${appendage}.${this.fileExtension}`
|
|
|
|
return sanitizeFilename(filename)
|
2022-03-22 01:24:38 +01:00
|
|
|
}
|
|
|
|
get targetPath() {
|
2024-11-08 00:26:51 +01:00
|
|
|
return filePathToPOSIX(Path.join(this.libraryItem.path, this.targetFilename))
|
2022-03-22 01:24:38 +01:00
|
|
|
}
|
|
|
|
get targetRelPath() {
|
2022-03-27 00:23:33 +01:00
|
|
|
return this.targetFilename
|
2022-03-22 01:24:38 +01:00
|
|
|
}
|
2022-04-24 02:41:06 +02:00
|
|
|
get libraryItemId() {
|
|
|
|
return this.libraryItem ? this.libraryItem.id : null
|
|
|
|
}
|
2022-03-22 01:24:38 +01:00
|
|
|
|
2023-02-27 03:56:07 +01:00
|
|
|
setData(podcastEpisode, libraryItem, isAutoDownload, libraryId) {
|
2023-07-05 01:14:44 +02:00
|
|
|
this.id = uuidv4()
|
2022-03-22 01:24:38 +01:00
|
|
|
this.podcastEpisode = podcastEpisode
|
2023-03-14 21:38:19 +01:00
|
|
|
|
|
|
|
const url = podcastEpisode.enclosure.url
|
2024-11-08 00:26:51 +01:00
|
|
|
if (decodeURIComponent(url) !== url) {
|
|
|
|
// Already encoded
|
2023-03-14 21:38:19 +01:00
|
|
|
this.url = url
|
|
|
|
} else {
|
|
|
|
this.url = encodeURI(url)
|
|
|
|
}
|
|
|
|
|
2022-03-22 01:24:38 +01:00
|
|
|
this.libraryItem = libraryItem
|
2022-08-16 00:35:13 +02:00
|
|
|
this.isAutoDownload = isAutoDownload
|
2022-03-22 01:24:38 +01:00
|
|
|
this.createdAt = Date.now()
|
2023-02-27 03:56:07 +01:00
|
|
|
this.libraryId = libraryId
|
2022-03-22 01:24:38 +01:00
|
|
|
}
|
2022-04-24 02:41:06 +02:00
|
|
|
|
|
|
|
setFinished(success) {
|
|
|
|
this.finishedAt = Date.now()
|
|
|
|
this.isFinished = true
|
|
|
|
this.failed = !success
|
|
|
|
}
|
2022-03-22 01:24:38 +01:00
|
|
|
}
|
2023-02-27 03:56:07 +01:00
|
|
|
module.exports = PodcastEpisodeDownload
|