diff --git a/client/components/AudioPlayer.vue b/client/components/AudioPlayer.vue index 1d45fa8d..1bdb78a6 100644 --- a/client/components/AudioPlayer.vue +++ b/client/components/AudioPlayer.vue @@ -91,7 +91,7 @@ export default { return { hlsInstance: null, staleHlsInstance: null, - volume: 0.5, + volume: 1, playbackRate: 1, trackWidth: 0, isPaused: true, diff --git a/client/components/modals/AccountModal.vue b/client/components/modals/AccountModal.vue index 2506f685..254ae2f1 100644 --- a/client/components/modals/AccountModal.vue +++ b/client/components/modals/AccountModal.vue @@ -151,9 +151,10 @@ export default { } }) .catch((error) => { - console.error('Failed to update account', error) this.processing = false - this.$toast.error('Failed to update account') + console.error('Failed to update account', error) + var errMsg = error.response ? error.response.data || '' : '' + this.$toast.error(errMsg || 'Failed to update account') }) }, submitCreateAccount() { @@ -176,9 +177,10 @@ export default { } }) .catch((error) => { - console.error('Failed to create account', error) this.processing = false - this.$toast.error('Failed to create account') + console.error('Failed to create account', error) + var errMsg = error.response ? error.response.data || '' : '' + this.$toast.error(errMsg || 'Failed to create account') }) }, toggleActive() { diff --git a/client/package.json b/client/package.json index 7f936969..73be827d 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-client", - "version": "1.4.12", + "version": "1.4.13", "description": "Audiobook manager and player", "main": "index.js", "scripts": { diff --git a/client/pages/audiobook/_id/edit.vue b/client/pages/audiobook/_id/edit.vue index 7e078bce..ee339cf4 100644 --- a/client/pages/audiobook/_id/edit.vue +++ b/client/pages/audiobook/_id/edit.vue @@ -67,6 +67,7 @@ # From Metadata # From Filename # From Probe + Raw Tags {{ trackData.filename }} @@ -74,6 +75,7 @@ {{ trackData.trackNumFromMeta }} {{ trackData.trackNumFromFilename }} {{ trackData.scanDataTrackNum }} + {{ JSON.stringify(trackData.rawTags || '') }} diff --git a/package.json b/package.json index 8861e419..6946d653 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "1.4.12", + "version": "1.4.13", "description": "Self-hosted audiobook server for managing and playing audiobooks", "main": "index.js", "scripts": { diff --git a/server/ApiController.js b/server/ApiController.js index b9a58d93..bd3c24e1 100644 --- a/server/ApiController.js +++ b/server/ApiController.js @@ -597,6 +597,13 @@ class ApiController { return res.sendStatus(403) } var account = req.body + + var username = account.username + var usernameExists = this.db.users.find(u => u.username.toLowerCase() === username.toLowerCase()) + if (usernameExists) { + return res.status(500).send('Username already taken') + } + account.id = (Math.trunc(Math.random() * 1000) + Date.now()).toString(36) account.pash = await this.auth.hashPass(account.password) delete account.password @@ -610,9 +617,7 @@ class ApiController { user: newUser.toJSONForBrowser() }) } else { - res.json({ - error: 'Failed to save new user' - }) + return res.status(500).send('Failed to save new user') } } @@ -628,6 +633,14 @@ class ApiController { } var account = req.body + + if (account.username !== undefined && account.username !== user.username) { + var usernameExists = this.db.users.find(u => u.username.toLowerCase() === account.username.toLowerCase()) + if (usernameExists) { + return res.status(500).send('Username already taken') + } + } + // Updating password if (account.password) { account.pash = await this.auth.hashPass(account.password) diff --git a/server/Auth.js b/server/Auth.js index 6cd175ec..88aee8dd 100644 --- a/server/Auth.js +++ b/server/Auth.js @@ -97,11 +97,11 @@ class Auth { } async login(req, res) { - var username = req.body.username + var username = (req.body.username || '').toLowerCase() var password = req.body.password || '' Logger.debug('Check Auth', username, !!password) - var user = this.users.find(u => u.username === username) + var user = this.users.find(u => u.username.toLowerCase() === username) if (!user || !user.isActive) { Logger.debug(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit}`) diff --git a/server/utils/audioFileScanner.js b/server/utils/audioFileScanner.js index ed35481e..19e358d5 100644 --- a/server/utils/audioFileScanner.js +++ b/server/utils/audioFileScanner.js @@ -11,9 +11,9 @@ function getDefaultAudioStream(audioStreams) { return defaultStream } -async function scan(path) { +async function scan(path, verbose = false) { Logger.debug(`Scanning path "${path}"`) - var probeData = await prober(path) + var probeData = await prober(path, verbose) if (!probeData || !probeData.audio_streams || !probeData.audio_streams.length) { return { error: 'Invalid audio file' @@ -62,6 +62,10 @@ async function scan(path) { } } + if (verbose && probeData.rawTags) { + finalData.rawTags = probeData.rawTags + } + return finalData } module.exports.scan = scan @@ -239,7 +243,7 @@ async function scanTrackNumbers(audiobook) { var scannedTrackNumData = [] for (let i = 0; i < tracks.length; i++) { var track = tracks[i] - var scanData = await scan(track.fullPath) + var scanData = await scan(track.fullPath, true) var trackNumFromMeta = getTrackNumberFromMeta(scanData) var book = audiobook.book || {} @@ -250,7 +254,8 @@ async function scanTrackNumbers(audiobook) { currentTrackNum: track.index, trackNumFromFilename, trackNumFromMeta, - scanDataTrackNum: scanData.file_tag_track + scanDataTrackNum: scanData.file_tag_track, + rawTags: scanData.rawTags || null }) } return scannedTrackNumData diff --git a/server/utils/prober.js b/server/utils/prober.js index e8c2c4d3..03bbdb55 100644 --- a/server/utils/prober.js +++ b/server/utils/prober.js @@ -135,11 +135,13 @@ function parseChapters(chapters) { }) } -function parseTags(format) { +function parseTags(format, verbose) { if (!format.tags) { return {} } - // Logger.debug('Tags', format.tags) + if (verbose) { + Logger.debug('Tags', format.tags) + } const tags = { file_tag_encoder: tryGrabTags(format, 'encoder', 'tsse', 'tss'), file_tag_encodedby: tryGrabTags(format, 'encoded_by', 'tenc', 'ten'), @@ -166,7 +168,8 @@ function parseTags(format) { file_tag_series: tryGrabTag(format, 'series'), file_tag_seriespart: tryGrabTag(format, 'series-part'), file_tag_genre1: tryGrabTags(format, 'tmp_genre1', 'genre1'), - file_tag_genre2: tryGrabTags(format, 'tmp_genre2', 'genre2') + file_tag_genre2: tryGrabTags(format, 'tmp_genre2', 'genre2'), + file_tag_genre: tryGrabTags(format, 'genre', 'genre') } for (const key in tags) { if (!tags[key]) { @@ -174,7 +177,7 @@ function parseTags(format) { } } - var keysToLookOutFor = ['file_tag_genre1', 'file_tag_genre2', 'file_tag_series', 'file_tag_seriespart', 'file_tag_movement', 'file_tag_movementname', 'file_tag_wwwaudiofile', 'file_tag_contentgroup', 'file_tag_releasetime'] + var keysToLookOutFor = ['file_tag_genre1', 'file_tag_genre2', 'file_tag_genre', 'file_tag_series', 'file_tag_seriespart', 'file_tag_movement', 'file_tag_movementname', 'file_tag_wwwaudiofile', 'file_tag_contentgroup', 'file_tag_releasetime'] var success = keysToLookOutFor.find(key => !!tags[key]) if (success) { Logger.debug('Notable!', success) @@ -182,7 +185,7 @@ function parseTags(format) { return tags } -function parseProbeData(data) { +function parseProbeData(data, verbose = false) { try { var { format, streams, chapters } = data var { format_long_name, duration, size, bit_rate } = format @@ -191,7 +194,7 @@ function parseProbeData(data) { var sizeMb = sizeBytes !== null ? Number((sizeBytes / (1024 * 1024)).toFixed(2)) : null // Logger.debug('Parsing Data for', Path.basename(format.filename)) - var tags = parseTags(format) + var tags = parseTags(format, verbose) var cleanedData = { format: format_long_name, duration: !isNaN(duration) ? Number(duration) : null, @@ -200,6 +203,9 @@ function parseProbeData(data) { bit_rate: !isNaN(bit_rate) ? Number(bit_rate) : null, ...tags } + if (verbose && format.tags) { + cleanedData.rawTags = format.tags + } const cleaned_streams = streams.map(s => parseMediaStreamInfo(s, streams, cleanedData.bit_rate)) cleanedData.video_stream = cleaned_streams.find(s => s.type === 'video') @@ -223,14 +229,14 @@ function parseProbeData(data) { } } -function probe(filepath) { +function probe(filepath, verbose = false) { return new Promise((resolve) => { Ffmpeg.ffprobe(filepath, ['-show_chapters'], (err, raw) => { if (err) { console.error(err) resolve(null) } else { - resolve(parseProbeData(raw)) + resolve(parseProbeData(raw, verbose)) } }) })