mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-02-03 16:59:41 +00:00
Merge remote-tracking branch 'origin/master' into auth_passportjs
This commit is contained in:
commit
812395b21b
90 changed files with 3469 additions and 1148 deletions
|
|
@ -1,5 +1,6 @@
|
|||
class DeviceInfo {
|
||||
constructor(deviceInfo = null) {
|
||||
this.deviceId = null
|
||||
this.ipAddress = null
|
||||
|
||||
// From User Agent (see: https://www.npmjs.com/package/ua-parser-js)
|
||||
|
|
@ -32,6 +33,7 @@ class DeviceInfo {
|
|||
|
||||
toJSON() {
|
||||
const obj = {
|
||||
deviceId: this.deviceId,
|
||||
ipAddress: this.ipAddress,
|
||||
browserName: this.browserName,
|
||||
browserVersion: this.browserVersion,
|
||||
|
|
@ -60,23 +62,42 @@ class DeviceInfo {
|
|||
return `${this.osName} ${this.osVersion} / ${this.browserName}`
|
||||
}
|
||||
|
||||
// When client doesn't send a device id
|
||||
getTempDeviceId() {
|
||||
const keys = [
|
||||
this.browserName,
|
||||
this.browserVersion,
|
||||
this.osName,
|
||||
this.osVersion,
|
||||
this.clientVersion,
|
||||
this.manufacturer,
|
||||
this.model,
|
||||
this.sdkVersion,
|
||||
this.ipAddress
|
||||
].map(k => k || '')
|
||||
return 'temp-' + Buffer.from(keys.join('-'), 'utf-8').toString('base64')
|
||||
}
|
||||
|
||||
setData(ip, ua, clientDeviceInfo, serverVersion) {
|
||||
this.deviceId = clientDeviceInfo?.deviceId || null
|
||||
this.ipAddress = ip || null
|
||||
|
||||
const uaObj = ua || {}
|
||||
this.browserName = uaObj.browser.name || null
|
||||
this.browserVersion = uaObj.browser.version || null
|
||||
this.osName = uaObj.os.name || null
|
||||
this.osVersion = uaObj.os.version || null
|
||||
this.deviceType = uaObj.device.type || null
|
||||
this.browserName = ua?.browser.name || null
|
||||
this.browserVersion = ua?.browser.version || null
|
||||
this.osName = ua?.os.name || null
|
||||
this.osVersion = ua?.os.version || null
|
||||
this.deviceType = ua?.device.type || null
|
||||
|
||||
const cdi = clientDeviceInfo || {}
|
||||
this.clientVersion = cdi.clientVersion || null
|
||||
this.manufacturer = cdi.manufacturer || null
|
||||
this.model = cdi.model || null
|
||||
this.sdkVersion = cdi.sdkVersion || null
|
||||
this.clientVersion = clientDeviceInfo?.clientVersion || null
|
||||
this.manufacturer = clientDeviceInfo?.manufacturer || null
|
||||
this.model = clientDeviceInfo?.model || null
|
||||
this.sdkVersion = clientDeviceInfo?.sdkVersion || null
|
||||
|
||||
this.serverVersion = serverVersion || null
|
||||
|
||||
if (!this.deviceId) {
|
||||
this.deviceId = this.getTempDeviceId()
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = DeviceInfo
|
||||
|
|
@ -55,7 +55,7 @@ class PlaybackSession {
|
|||
libraryItemId: this.libraryItemId,
|
||||
episodeId: this.episodeId,
|
||||
mediaType: this.mediaType,
|
||||
mediaMetadata: this.mediaMetadata ? this.mediaMetadata.toJSON() : null,
|
||||
mediaMetadata: this.mediaMetadata?.toJSON() || null,
|
||||
chapters: (this.chapters || []).map(c => ({ ...c })),
|
||||
displayTitle: this.displayTitle,
|
||||
displayAuthor: this.displayAuthor,
|
||||
|
|
@ -63,7 +63,7 @@ class PlaybackSession {
|
|||
duration: this.duration,
|
||||
playMethod: this.playMethod,
|
||||
mediaPlayer: this.mediaPlayer,
|
||||
deviceInfo: this.deviceInfo ? this.deviceInfo.toJSON() : null,
|
||||
deviceInfo: this.deviceInfo?.toJSON() || null,
|
||||
date: this.date,
|
||||
dayOfWeek: this.dayOfWeek,
|
||||
timeListening: this.timeListening,
|
||||
|
|
@ -82,7 +82,7 @@ class PlaybackSession {
|
|||
libraryItemId: this.libraryItemId,
|
||||
episodeId: this.episodeId,
|
||||
mediaType: this.mediaType,
|
||||
mediaMetadata: this.mediaMetadata ? this.mediaMetadata.toJSON() : null,
|
||||
mediaMetadata: this.mediaMetadata?.toJSON() || null,
|
||||
chapters: (this.chapters || []).map(c => ({ ...c })),
|
||||
displayTitle: this.displayTitle,
|
||||
displayAuthor: this.displayAuthor,
|
||||
|
|
@ -90,7 +90,7 @@ class PlaybackSession {
|
|||
duration: this.duration,
|
||||
playMethod: this.playMethod,
|
||||
mediaPlayer: this.mediaPlayer,
|
||||
deviceInfo: this.deviceInfo ? this.deviceInfo.toJSON() : null,
|
||||
deviceInfo: this.deviceInfo?.toJSON() || null,
|
||||
date: this.date,
|
||||
dayOfWeek: this.dayOfWeek,
|
||||
timeListening: this.timeListening,
|
||||
|
|
@ -151,6 +151,10 @@ class PlaybackSession {
|
|||
return Math.max(0, Math.min(this.currentTime / this.duration, 1))
|
||||
}
|
||||
|
||||
get deviceId() {
|
||||
return this.deviceInfo?.deviceId
|
||||
}
|
||||
|
||||
get deviceDescription() {
|
||||
if (!this.deviceInfo) return 'No Device Info'
|
||||
return this.deviceInfo.deviceDescription
|
||||
|
|
|
|||
|
|
@ -41,8 +41,12 @@ class PodcastEpisodeDownload {
|
|||
}
|
||||
}
|
||||
|
||||
get urlFileExtension() {
|
||||
const cleanUrl = this.url.split('?')[0] // Remove query string
|
||||
return Path.extname(cleanUrl).substring(1).toLowerCase()
|
||||
}
|
||||
get fileExtension() {
|
||||
const extname = Path.extname(this.url).substring(1).toLowerCase()
|
||||
const extname = this.urlFileExtension
|
||||
if (globals.SupportedAudioTypes.includes(extname)) return extname
|
||||
return 'mp3'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
const Path = require('path')
|
||||
const { getId, cleanStringForSearch } = require('../../utils/index')
|
||||
const Logger = require('../../Logger')
|
||||
const { getId, cleanStringForSearch, areEquivalent, copyValue } = require('../../utils/index')
|
||||
const AudioFile = require('../files/AudioFile')
|
||||
const AudioTrack = require('../files/AudioTrack')
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ class PodcastEpisode {
|
|||
this.description = null
|
||||
this.enclosure = null
|
||||
this.pubDate = null
|
||||
this.chapters = []
|
||||
|
||||
this.audioFile = null
|
||||
this.publishedAt = null
|
||||
|
|
@ -40,6 +42,7 @@ class PodcastEpisode {
|
|||
this.description = episode.description
|
||||
this.enclosure = episode.enclosure ? { ...episode.enclosure } : null
|
||||
this.pubDate = episode.pubDate
|
||||
this.chapters = episode.chapters?.map(ch => ({ ...ch })) || []
|
||||
this.audioFile = new AudioFile(episode.audioFile)
|
||||
this.publishedAt = episode.publishedAt
|
||||
this.addedAt = episode.addedAt
|
||||
|
|
@ -61,6 +64,7 @@ class PodcastEpisode {
|
|||
description: this.description,
|
||||
enclosure: this.enclosure ? { ...this.enclosure } : null,
|
||||
pubDate: this.pubDate,
|
||||
chapters: this.chapters.map(ch => ({ ...ch })),
|
||||
audioFile: this.audioFile.toJSON(),
|
||||
publishedAt: this.publishedAt,
|
||||
addedAt: this.addedAt,
|
||||
|
|
@ -81,6 +85,7 @@ class PodcastEpisode {
|
|||
description: this.description,
|
||||
enclosure: this.enclosure ? { ...this.enclosure } : null,
|
||||
pubDate: this.pubDate,
|
||||
chapters: this.chapters.map(ch => ({ ...ch })),
|
||||
audioFile: this.audioFile.toJSON(),
|
||||
audioTrack: this.audioTrack.toJSON(),
|
||||
publishedAt: this.publishedAt,
|
||||
|
|
@ -106,6 +111,10 @@ class PodcastEpisode {
|
|||
get enclosureUrl() {
|
||||
return this.enclosure ? this.enclosure.url : null
|
||||
}
|
||||
get pubYear() {
|
||||
if (!this.publishedAt) return null
|
||||
return new Date(this.publishedAt).getFullYear()
|
||||
}
|
||||
|
||||
setData(data, index = 1) {
|
||||
this.id = getId('ep')
|
||||
|
|
@ -128,6 +137,10 @@ class PodcastEpisode {
|
|||
this.audioFile = audioFile
|
||||
this.title = Path.basename(audioFile.metadata.filename, Path.extname(audioFile.metadata.filename))
|
||||
this.index = index
|
||||
|
||||
this.setDataFromAudioMetaTags(audioFile.metaTags, true)
|
||||
|
||||
this.chapters = audioFile.chapters?.map((c) => ({ ...c }))
|
||||
this.addedAt = Date.now()
|
||||
this.updatedAt = Date.now()
|
||||
}
|
||||
|
|
@ -135,8 +148,8 @@ class PodcastEpisode {
|
|||
update(payload) {
|
||||
let hasUpdates = false
|
||||
for (const key in this.toJSON()) {
|
||||
if (payload[key] != undefined && payload[key] != this[key]) {
|
||||
this[key] = payload[key]
|
||||
if (payload[key] != undefined && !areEquivalent(payload[key], this[key])) {
|
||||
this[key] = copyValue(payload[key])
|
||||
hasUpdates = true
|
||||
}
|
||||
}
|
||||
|
|
@ -164,5 +177,76 @@ class PodcastEpisode {
|
|||
searchQuery(query) {
|
||||
return cleanStringForSearch(this.title).includes(query)
|
||||
}
|
||||
|
||||
setDataFromAudioMetaTags(audioFileMetaTags, overrideExistingDetails = false) {
|
||||
if (!audioFileMetaTags) return false
|
||||
|
||||
const MetadataMapArray = [
|
||||
{
|
||||
tag: 'tagComment',
|
||||
altTag: 'tagSubtitle',
|
||||
key: 'description'
|
||||
},
|
||||
{
|
||||
tag: 'tagSubtitle',
|
||||
key: 'subtitle'
|
||||
},
|
||||
{
|
||||
tag: 'tagDate',
|
||||
key: 'pubDate'
|
||||
},
|
||||
{
|
||||
tag: 'tagDisc',
|
||||
key: 'season',
|
||||
},
|
||||
{
|
||||
tag: 'tagTrack',
|
||||
altTag: 'tagSeriesPart',
|
||||
key: 'episode'
|
||||
},
|
||||
{
|
||||
tag: 'tagTitle',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
tag: 'tagEpisodeType',
|
||||
key: 'episodeType'
|
||||
}
|
||||
]
|
||||
|
||||
MetadataMapArray.forEach((mapping) => {
|
||||
let value = audioFileMetaTags[mapping.tag]
|
||||
let tagToUse = mapping.tag
|
||||
if (!value && mapping.altTag) {
|
||||
tagToUse = mapping.altTag
|
||||
value = audioFileMetaTags[mapping.altTag]
|
||||
}
|
||||
|
||||
if (value && typeof value === 'string') {
|
||||
value = value.trim() // Trim whitespace
|
||||
|
||||
if (mapping.key === 'pubDate' && (!this.pubDate || overrideExistingDetails)) {
|
||||
const pubJsDate = new Date(value)
|
||||
if (pubJsDate && !isNaN(pubJsDate)) {
|
||||
this.publishedAt = pubJsDate.valueOf()
|
||||
this.pubDate = value
|
||||
Logger.debug(`[PodcastEpisode] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${this[mapping.key]}`)
|
||||
} else {
|
||||
Logger.warn(`[PodcastEpisode] Mapping pubDate with tag ${tagToUse} has invalid date "${value}"`)
|
||||
}
|
||||
} else if (mapping.key === 'episodeType' && (!this.episodeType || overrideExistingDetails)) {
|
||||
if (['full', 'trailer', 'bonus'].includes(value)) {
|
||||
this.episodeType = value
|
||||
Logger.debug(`[PodcastEpisode] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${this[mapping.key]}`)
|
||||
} else {
|
||||
Logger.warn(`[PodcastEpisode] Mapping episodeType with invalid value "${value}". Must be one of [full, trailer, bonus].`)
|
||||
}
|
||||
} else if (!this[mapping.key] || overrideExistingDetails) {
|
||||
this[mapping.key] = value
|
||||
Logger.debug(`[PodcastEpisode] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${this[mapping.key]}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
module.exports = PodcastEpisode
|
||||
|
|
|
|||
|
|
@ -166,7 +166,11 @@ class Podcast {
|
|||
}
|
||||
|
||||
removeFileWithInode(inode) {
|
||||
this.episodes = this.episodes.filter(ep => ep.ino !== inode)
|
||||
const hasEpisode = this.episodes.some(ep => ep.audioFile.ino === inode)
|
||||
if (hasEpisode) {
|
||||
this.episodes = this.episodes.filter(ep => ep.audioFile.ino !== inode)
|
||||
}
|
||||
return hasEpisode
|
||||
}
|
||||
|
||||
findFileWithInode(inode) {
|
||||
|
|
@ -175,6 +179,10 @@ class Podcast {
|
|||
return null
|
||||
}
|
||||
|
||||
findEpisodeWithInode(inode) {
|
||||
return this.episodes.find(ep => ep.audioFile.ino === inode)
|
||||
}
|
||||
|
||||
setData(mediaData) {
|
||||
this.metadata = new PodcastMetadata()
|
||||
if (mediaData.metadata) {
|
||||
|
|
@ -315,5 +323,13 @@ class Podcast {
|
|||
getEpisode(episodeId) {
|
||||
return this.episodes.find(ep => ep.id == episodeId)
|
||||
}
|
||||
|
||||
// Audio file metadata tags map to podcast details
|
||||
setMetadataFromAudioFile(overrideExistingDetails = false) {
|
||||
if (!this.episodes.length) return false
|
||||
const audioFile = this.episodes[0].audioFile
|
||||
if (!audioFile?.metaTags) return false
|
||||
return this.metadata.setDataFromAudioMetaTags(audioFile.metaTags, overrideExistingDetails)
|
||||
}
|
||||
}
|
||||
module.exports = Podcast
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
class AudioMetaTags {
|
||||
constructor(metadata) {
|
||||
this.tagAlbum = null
|
||||
this.tagAlbumSort = null
|
||||
this.tagArtist = null
|
||||
this.tagArtistSort = null
|
||||
this.tagGenre = null
|
||||
this.tagTitle = null
|
||||
this.tagTitleSort = null
|
||||
this.tagSeries = null
|
||||
this.tagSeriesPart = null
|
||||
this.tagTrack = null
|
||||
|
|
@ -20,6 +23,9 @@ class AudioMetaTags {
|
|||
this.tagIsbn = null
|
||||
this.tagLanguage = null
|
||||
this.tagASIN = null
|
||||
this.tagItunesId = null
|
||||
this.tagPodcastType = null
|
||||
this.tagEpisodeType = null
|
||||
this.tagOverdriveMediaMarker = null
|
||||
this.tagOriginalYear = null
|
||||
this.tagReleaseCountry = null
|
||||
|
|
@ -94,9 +100,12 @@ class AudioMetaTags {
|
|||
|
||||
construct(metadata) {
|
||||
this.tagAlbum = metadata.tagAlbum || null
|
||||
this.tagAlbumSort = metadata.tagAlbumSort || null
|
||||
this.tagArtist = metadata.tagArtist || null
|
||||
this.tagArtistSort = metadata.tagArtistSort || null
|
||||
this.tagGenre = metadata.tagGenre || null
|
||||
this.tagTitle = metadata.tagTitle || null
|
||||
this.tagTitleSort = metadata.tagTitleSort || null
|
||||
this.tagSeries = metadata.tagSeries || null
|
||||
this.tagSeriesPart = metadata.tagSeriesPart || null
|
||||
this.tagTrack = metadata.tagTrack || null
|
||||
|
|
@ -113,6 +122,9 @@ class AudioMetaTags {
|
|||
this.tagIsbn = metadata.tagIsbn || null
|
||||
this.tagLanguage = metadata.tagLanguage || null
|
||||
this.tagASIN = metadata.tagASIN || null
|
||||
this.tagItunesId = metadata.tagItunesId || null
|
||||
this.tagPodcastType = metadata.tagPodcastType || null
|
||||
this.tagEpisodeType = metadata.tagEpisodeType || null
|
||||
this.tagOverdriveMediaMarker = metadata.tagOverdriveMediaMarker || null
|
||||
this.tagOriginalYear = metadata.tagOriginalYear || null
|
||||
this.tagReleaseCountry = metadata.tagReleaseCountry || null
|
||||
|
|
@ -128,9 +140,12 @@ class AudioMetaTags {
|
|||
// Data parsed in prober.js
|
||||
setData(payload) {
|
||||
this.tagAlbum = payload.file_tag_album || null
|
||||
this.tagAlbumSort = payload.file_tag_albumsort || null
|
||||
this.tagArtist = payload.file_tag_artist || null
|
||||
this.tagArtistSort = payload.file_tag_artistsort || null
|
||||
this.tagGenre = payload.file_tag_genre || null
|
||||
this.tagTitle = payload.file_tag_title || null
|
||||
this.tagTitleSort = payload.file_tag_titlesort || null
|
||||
this.tagSeries = payload.file_tag_series || null
|
||||
this.tagSeriesPart = payload.file_tag_seriespart || null
|
||||
this.tagTrack = payload.file_tag_track || null
|
||||
|
|
@ -147,6 +162,9 @@ class AudioMetaTags {
|
|||
this.tagIsbn = payload.file_tag_isbn || null
|
||||
this.tagLanguage = payload.file_tag_language || null
|
||||
this.tagASIN = payload.file_tag_asin || null
|
||||
this.tagItunesId = payload.file_tag_itunesid || null
|
||||
this.tagPodcastType = payload.file_tag_podcasttype || null
|
||||
this.tagEpisodeType = payload.file_tag_episodetype || null
|
||||
this.tagOverdriveMediaMarker = payload.file_tag_overdrive_media_marker || null
|
||||
this.tagOriginalYear = payload.file_tag_originalyear || null
|
||||
this.tagReleaseCountry = payload.file_tag_releasecountry || null
|
||||
|
|
@ -166,9 +184,12 @@ class AudioMetaTags {
|
|||
updateData(payload) {
|
||||
const dataMap = {
|
||||
tagAlbum: payload.file_tag_album || null,
|
||||
tagAlbumSort: payload.file_tag_albumsort || null,
|
||||
tagArtist: payload.file_tag_artist || null,
|
||||
tagArtistSort: payload.file_tag_artistsort || null,
|
||||
tagGenre: payload.file_tag_genre || null,
|
||||
tagTitle: payload.file_tag_title || null,
|
||||
tagTitleSort: payload.file_tag_titlesort || null,
|
||||
tagSeries: payload.file_tag_series || null,
|
||||
tagSeriesPart: payload.file_tag_seriespart || null,
|
||||
tagTrack: payload.file_tag_track || null,
|
||||
|
|
@ -185,6 +206,9 @@ class AudioMetaTags {
|
|||
tagIsbn: payload.file_tag_isbn || null,
|
||||
tagLanguage: payload.file_tag_language || null,
|
||||
tagASIN: payload.file_tag_asin || null,
|
||||
tagItunesId: payload.file_tag_itunesid || null,
|
||||
tagPodcastType: payload.file_tag_podcasttype || null,
|
||||
tagEpisodeType: payload.file_tag_episodetype || null,
|
||||
tagOverdriveMediaMarker: payload.file_tag_overdrive_media_marker || null,
|
||||
tagOriginalYear: payload.file_tag_originalyear || null,
|
||||
tagReleaseCountry: payload.file_tag_releasecountry || null,
|
||||
|
|
|
|||
|
|
@ -136,5 +136,74 @@ class PodcastMetadata {
|
|||
}
|
||||
return hasUpdates
|
||||
}
|
||||
|
||||
setDataFromAudioMetaTags(audioFileMetaTags, overrideExistingDetails = false) {
|
||||
const MetadataMapArray = [
|
||||
{
|
||||
tag: 'tagAlbum',
|
||||
altTag: 'tagSeries',
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
tag: 'tagArtist',
|
||||
key: 'author'
|
||||
},
|
||||
{
|
||||
tag: 'tagGenre',
|
||||
key: 'genres'
|
||||
},
|
||||
{
|
||||
tag: 'tagLanguage',
|
||||
key: 'language'
|
||||
},
|
||||
{
|
||||
tag: 'tagItunesId',
|
||||
key: 'itunesId'
|
||||
},
|
||||
{
|
||||
tag: 'tagPodcastType',
|
||||
key: 'type',
|
||||
}
|
||||
]
|
||||
|
||||
const updatePayload = {}
|
||||
|
||||
MetadataMapArray.forEach((mapping) => {
|
||||
let value = audioFileMetaTags[mapping.tag]
|
||||
let tagToUse = mapping.tag
|
||||
if (!value && mapping.altTag) {
|
||||
value = audioFileMetaTags[mapping.altTag]
|
||||
tagToUse = mapping.altTag
|
||||
}
|
||||
|
||||
if (value && typeof value === 'string') {
|
||||
value = value.trim() // Trim whitespace
|
||||
|
||||
if (mapping.key === 'genres' && (!this.genres.length || overrideExistingDetails)) {
|
||||
updatePayload.genres = this.parseGenresTag(value)
|
||||
Logger.debug(`[Podcast] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${updatePayload.genres.join(', ')}`)
|
||||
} else if (!this[mapping.key] || overrideExistingDetails) {
|
||||
updatePayload[mapping.key] = value
|
||||
Logger.debug(`[Podcast] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${updatePayload[mapping.key]}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (Object.keys(updatePayload).length) {
|
||||
return this.update(updatePayload)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
parseGenresTag(genreTag) {
|
||||
if (!genreTag || !genreTag.length) return []
|
||||
const separators = ['/', '//', ';']
|
||||
for (let i = 0; i < separators.length; i++) {
|
||||
if (genreTag.includes(separators[i])) {
|
||||
return genreTag.split(separators[i]).map(genre => genre.trim()).filter(g => !!g)
|
||||
}
|
||||
}
|
||||
return [genreTag]
|
||||
}
|
||||
}
|
||||
module.exports = PodcastMetadata
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ class MediaProgress {
|
|||
this.isFinished = false
|
||||
this.hideFromContinueListening = false
|
||||
|
||||
this.ebookLocation = null // current cfi tag
|
||||
this.ebookProgress = null // 0 to 1
|
||||
|
||||
this.lastUpdate = null
|
||||
this.startedAt = null
|
||||
this.finishedAt = null
|
||||
|
|
@ -29,6 +32,8 @@ class MediaProgress {
|
|||
currentTime: this.currentTime,
|
||||
isFinished: this.isFinished,
|
||||
hideFromContinueListening: this.hideFromContinueListening,
|
||||
ebookLocation: this.ebookLocation,
|
||||
ebookProgress: this.ebookProgress,
|
||||
lastUpdate: this.lastUpdate,
|
||||
startedAt: this.startedAt,
|
||||
finishedAt: this.finishedAt
|
||||
|
|
@ -44,13 +49,15 @@ class MediaProgress {
|
|||
this.currentTime = progress.currentTime
|
||||
this.isFinished = !!progress.isFinished
|
||||
this.hideFromContinueListening = !!progress.hideFromContinueListening
|
||||
this.ebookLocation = progress.ebookLocation || null
|
||||
this.ebookProgress = progress.ebookProgress
|
||||
this.lastUpdate = progress.lastUpdate
|
||||
this.startedAt = progress.startedAt
|
||||
this.finishedAt = progress.finishedAt || null
|
||||
}
|
||||
|
||||
get inProgress() {
|
||||
return !this.isFinished && this.progress > 0
|
||||
return !this.isFinished && (this.progress > 0 || this.ebookLocation != null)
|
||||
}
|
||||
|
||||
setData(libraryItemId, progress, episodeId = null) {
|
||||
|
|
@ -62,6 +69,8 @@ class MediaProgress {
|
|||
this.currentTime = progress.currentTime || 0
|
||||
this.isFinished = !!progress.isFinished || this.progress == 1
|
||||
this.hideFromContinueListening = !!progress.hideFromContinueListening
|
||||
this.ebookLocation = progress.ebookLocation
|
||||
this.ebookProgress = Math.min(1, (progress.ebookProgress || 0))
|
||||
this.lastUpdate = Date.now()
|
||||
this.finishedAt = null
|
||||
if (this.isFinished) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ class User {
|
|||
this.seriesHideFromContinueListening = [] // Series IDs that should not show on home page continue listening
|
||||
this.bookmarks = []
|
||||
|
||||
this.settings = {} // TODO: Remove after mobile release v0.9.61-beta
|
||||
this.permissions = {}
|
||||
this.librariesAccessible = [] // Library IDs (Empty if ALL libraries)
|
||||
this.itemTagsAccessible = [] // Empty if ALL item tags accessible
|
||||
|
|
@ -59,15 +58,6 @@ class User {
|
|||
return !!this.pash && !!this.pash.length
|
||||
}
|
||||
|
||||
// TODO: Remove after mobile release v0.9.61-beta
|
||||
getDefaultUserSettings() {
|
||||
return {
|
||||
mobileOrderBy: 'recent',
|
||||
mobileOrderDesc: true,
|
||||
mobileFilterBy: 'all'
|
||||
}
|
||||
}
|
||||
|
||||
getDefaultUserPermissions() {
|
||||
return {
|
||||
download: true,
|
||||
|
|
@ -94,19 +84,18 @@ class User {
|
|||
isLocked: this.isLocked,
|
||||
lastSeen: this.lastSeen,
|
||||
createdAt: this.createdAt,
|
||||
settings: this.settings, // TODO: Remove after mobile release v0.9.61-beta
|
||||
permissions: this.permissions,
|
||||
librariesAccessible: [...this.librariesAccessible],
|
||||
itemTagsAccessible: [...this.itemTagsAccessible]
|
||||
}
|
||||
}
|
||||
|
||||
toJSONForBrowser() {
|
||||
return {
|
||||
toJSONForBrowser(hideRootToken = false, minimal = false) {
|
||||
const json = {
|
||||
id: this.id,
|
||||
username: this.username,
|
||||
type: this.type,
|
||||
token: this.token,
|
||||
token: (this.type === 'root' && hideRootToken) ? '' : this.token,
|
||||
mediaProgress: this.mediaProgress ? this.mediaProgress.map(li => li.toJSON()) : [],
|
||||
seriesHideFromContinueListening: [...this.seriesHideFromContinueListening],
|
||||
bookmarks: this.bookmarks ? this.bookmarks.map(b => b.toJSON()) : [],
|
||||
|
|
@ -114,11 +103,15 @@ class User {
|
|||
isLocked: this.isLocked,
|
||||
lastSeen: this.lastSeen,
|
||||
createdAt: this.createdAt,
|
||||
settings: this.settings, // TODO: Remove after mobile release v0.9.61-beta
|
||||
permissions: this.permissions,
|
||||
librariesAccessible: [...this.librariesAccessible],
|
||||
itemTagsAccessible: [...this.itemTagsAccessible]
|
||||
}
|
||||
if (minimal) {
|
||||
delete json.mediaProgress
|
||||
delete json.bookmarks
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
// Data broadcasted
|
||||
|
|
@ -166,7 +159,6 @@ class User {
|
|||
this.isLocked = user.type === 'root' ? false : !!user.isLocked
|
||||
this.lastSeen = user.lastSeen || null
|
||||
this.createdAt = user.createdAt || Date.now()
|
||||
this.settings = user.settings || this.getDefaultUserSettings() // TODO: Remove after mobile release v0.9.61-beta
|
||||
this.permissions = user.permissions || this.getDefaultUserPermissions()
|
||||
// Upload permission added v1.1.13, make sure root user has upload permissions
|
||||
if (this.type === 'root' && !this.permissions.upload) this.permissions.upload = true
|
||||
|
|
@ -343,33 +335,6 @@ class User {
|
|||
return true
|
||||
}
|
||||
|
||||
// TODO: Remove after mobile release v0.9.61-beta
|
||||
// Returns Boolean If update was made
|
||||
updateSettings(settings) {
|
||||
if (!this.settings) {
|
||||
this.settings = { ...settings }
|
||||
return true
|
||||
}
|
||||
var madeUpdates = false
|
||||
|
||||
for (const key in this.settings) {
|
||||
if (settings[key] !== undefined && this.settings[key] !== settings[key]) {
|
||||
this.settings[key] = settings[key]
|
||||
madeUpdates = true
|
||||
}
|
||||
}
|
||||
|
||||
// Check if new settings update has keys not currently in user settings
|
||||
for (const key in settings) {
|
||||
if (settings[key] !== undefined && this.settings[key] === undefined) {
|
||||
this.settings[key] = settings[key]
|
||||
madeUpdates = true
|
||||
}
|
||||
}
|
||||
|
||||
return madeUpdates
|
||||
}
|
||||
|
||||
checkCanAccessLibrary(libraryId) {
|
||||
if (this.permissions.accessAllLibraries) return true
|
||||
if (!this.librariesAccessible) return false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue