mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-03 00:06:46 +01:00
Change: audio player default volume to 100% #118, Change: username case insensitive #117, Fix: allowing multiple users of the same name, Added: experimental scan audio tracks show raw tags #114
This commit is contained in:
parent
09aed354b3
commit
7d9ed75a28
@ -91,7 +91,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
hlsInstance: null,
|
hlsInstance: null,
|
||||||
staleHlsInstance: null,
|
staleHlsInstance: null,
|
||||||
volume: 0.5,
|
volume: 1,
|
||||||
playbackRate: 1,
|
playbackRate: 1,
|
||||||
trackWidth: 0,
|
trackWidth: 0,
|
||||||
isPaused: true,
|
isPaused: true,
|
||||||
|
@ -151,9 +151,10 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to update account', error)
|
|
||||||
this.processing = false
|
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() {
|
submitCreateAccount() {
|
||||||
@ -176,9 +177,10 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to create account', error)
|
|
||||||
this.processing = false
|
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() {
|
toggleActive() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "1.4.12",
|
"version": "1.4.13",
|
||||||
"description": "Audiobook manager and player",
|
"description": "Audiobook manager and player",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
<th class="w-32"># From Metadata</th>
|
<th class="w-32"># From Metadata</th>
|
||||||
<th class="w-32"># From Filename</th>
|
<th class="w-32"># From Filename</th>
|
||||||
<th class="w-32"># From Probe</th>
|
<th class="w-32"># From Probe</th>
|
||||||
|
<th class="w-32">Raw Tags</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="trackData in trackNumData" :key="trackData.filename">
|
<tr v-for="trackData in trackNumData" :key="trackData.filename">
|
||||||
<td class="text-xs">{{ trackData.filename }}</td>
|
<td class="text-xs">{{ trackData.filename }}</td>
|
||||||
@ -74,6 +75,7 @@
|
|||||||
<td class="text-center">{{ trackData.trackNumFromMeta }}</td>
|
<td class="text-center">{{ trackData.trackNumFromMeta }}</td>
|
||||||
<td class="text-center">{{ trackData.trackNumFromFilename }}</td>
|
<td class="text-center">{{ trackData.trackNumFromFilename }}</td>
|
||||||
<td class="text-center">{{ trackData.scanDataTrackNum }}</td>
|
<td class="text-center">{{ trackData.scanDataTrackNum }}</td>
|
||||||
|
<td class="text-left text-xs">{{ JSON.stringify(trackData.rawTags || '') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "1.4.12",
|
"version": "1.4.13",
|
||||||
"description": "Self-hosted audiobook server for managing and playing audiobooks",
|
"description": "Self-hosted audiobook server for managing and playing audiobooks",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -597,6 +597,13 @@ class ApiController {
|
|||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
var account = req.body
|
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.id = (Math.trunc(Math.random() * 1000) + Date.now()).toString(36)
|
||||||
account.pash = await this.auth.hashPass(account.password)
|
account.pash = await this.auth.hashPass(account.password)
|
||||||
delete account.password
|
delete account.password
|
||||||
@ -610,9 +617,7 @@ class ApiController {
|
|||||||
user: newUser.toJSONForBrowser()
|
user: newUser.toJSONForBrowser()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
res.json({
|
return res.status(500).send('Failed to save new user')
|
||||||
error: 'Failed to save new user'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,6 +633,14 @@ class ApiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var account = req.body
|
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
|
// Updating password
|
||||||
if (account.password) {
|
if (account.password) {
|
||||||
account.pash = await this.auth.hashPass(account.password)
|
account.pash = await this.auth.hashPass(account.password)
|
||||||
|
@ -97,11 +97,11 @@ class Auth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async login(req, res) {
|
async login(req, res) {
|
||||||
var username = req.body.username
|
var username = (req.body.username || '').toLowerCase()
|
||||||
var password = req.body.password || ''
|
var password = req.body.password || ''
|
||||||
Logger.debug('Check Auth', username, !!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) {
|
if (!user || !user.isActive) {
|
||||||
Logger.debug(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit}`)
|
Logger.debug(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit}`)
|
||||||
|
@ -11,9 +11,9 @@ function getDefaultAudioStream(audioStreams) {
|
|||||||
return defaultStream
|
return defaultStream
|
||||||
}
|
}
|
||||||
|
|
||||||
async function scan(path) {
|
async function scan(path, verbose = false) {
|
||||||
Logger.debug(`Scanning path "${path}"`)
|
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) {
|
if (!probeData || !probeData.audio_streams || !probeData.audio_streams.length) {
|
||||||
return {
|
return {
|
||||||
error: 'Invalid audio file'
|
error: 'Invalid audio file'
|
||||||
@ -62,6 +62,10 @@ async function scan(path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verbose && probeData.rawTags) {
|
||||||
|
finalData.rawTags = probeData.rawTags
|
||||||
|
}
|
||||||
|
|
||||||
return finalData
|
return finalData
|
||||||
}
|
}
|
||||||
module.exports.scan = scan
|
module.exports.scan = scan
|
||||||
@ -239,7 +243,7 @@ async function scanTrackNumbers(audiobook) {
|
|||||||
var scannedTrackNumData = []
|
var scannedTrackNumData = []
|
||||||
for (let i = 0; i < tracks.length; i++) {
|
for (let i = 0; i < tracks.length; i++) {
|
||||||
var track = tracks[i]
|
var track = tracks[i]
|
||||||
var scanData = await scan(track.fullPath)
|
var scanData = await scan(track.fullPath, true)
|
||||||
|
|
||||||
var trackNumFromMeta = getTrackNumberFromMeta(scanData)
|
var trackNumFromMeta = getTrackNumberFromMeta(scanData)
|
||||||
var book = audiobook.book || {}
|
var book = audiobook.book || {}
|
||||||
@ -250,7 +254,8 @@ async function scanTrackNumbers(audiobook) {
|
|||||||
currentTrackNum: track.index,
|
currentTrackNum: track.index,
|
||||||
trackNumFromFilename,
|
trackNumFromFilename,
|
||||||
trackNumFromMeta,
|
trackNumFromMeta,
|
||||||
scanDataTrackNum: scanData.file_tag_track
|
scanDataTrackNum: scanData.file_tag_track,
|
||||||
|
rawTags: scanData.rawTags || null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return scannedTrackNumData
|
return scannedTrackNumData
|
||||||
|
@ -135,11 +135,13 @@ function parseChapters(chapters) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTags(format) {
|
function parseTags(format, verbose) {
|
||||||
if (!format.tags) {
|
if (!format.tags) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
// Logger.debug('Tags', format.tags)
|
if (verbose) {
|
||||||
|
Logger.debug('Tags', format.tags)
|
||||||
|
}
|
||||||
const tags = {
|
const tags = {
|
||||||
file_tag_encoder: tryGrabTags(format, 'encoder', 'tsse', 'tss'),
|
file_tag_encoder: tryGrabTags(format, 'encoder', 'tsse', 'tss'),
|
||||||
file_tag_encodedby: tryGrabTags(format, 'encoded_by', 'tenc', 'ten'),
|
file_tag_encodedby: tryGrabTags(format, 'encoded_by', 'tenc', 'ten'),
|
||||||
@ -166,7 +168,8 @@ function parseTags(format) {
|
|||||||
file_tag_series: tryGrabTag(format, 'series'),
|
file_tag_series: tryGrabTag(format, 'series'),
|
||||||
file_tag_seriespart: tryGrabTag(format, 'series-part'),
|
file_tag_seriespart: tryGrabTag(format, 'series-part'),
|
||||||
file_tag_genre1: tryGrabTags(format, 'tmp_genre1', 'genre1'),
|
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) {
|
for (const key in tags) {
|
||||||
if (!tags[key]) {
|
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])
|
var success = keysToLookOutFor.find(key => !!tags[key])
|
||||||
if (success) {
|
if (success) {
|
||||||
Logger.debug('Notable!', success)
|
Logger.debug('Notable!', success)
|
||||||
@ -182,7 +185,7 @@ function parseTags(format) {
|
|||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseProbeData(data) {
|
function parseProbeData(data, verbose = false) {
|
||||||
try {
|
try {
|
||||||
var { format, streams, chapters } = data
|
var { format, streams, chapters } = data
|
||||||
var { format_long_name, duration, size, bit_rate } = format
|
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
|
var sizeMb = sizeBytes !== null ? Number((sizeBytes / (1024 * 1024)).toFixed(2)) : null
|
||||||
|
|
||||||
// Logger.debug('Parsing Data for', Path.basename(format.filename))
|
// Logger.debug('Parsing Data for', Path.basename(format.filename))
|
||||||
var tags = parseTags(format)
|
var tags = parseTags(format, verbose)
|
||||||
var cleanedData = {
|
var cleanedData = {
|
||||||
format: format_long_name,
|
format: format_long_name,
|
||||||
duration: !isNaN(duration) ? Number(duration) : null,
|
duration: !isNaN(duration) ? Number(duration) : null,
|
||||||
@ -200,6 +203,9 @@ function parseProbeData(data) {
|
|||||||
bit_rate: !isNaN(bit_rate) ? Number(bit_rate) : null,
|
bit_rate: !isNaN(bit_rate) ? Number(bit_rate) : null,
|
||||||
...tags
|
...tags
|
||||||
}
|
}
|
||||||
|
if (verbose && format.tags) {
|
||||||
|
cleanedData.rawTags = format.tags
|
||||||
|
}
|
||||||
|
|
||||||
const cleaned_streams = streams.map(s => parseMediaStreamInfo(s, streams, cleanedData.bit_rate))
|
const cleaned_streams = streams.map(s => parseMediaStreamInfo(s, streams, cleanedData.bit_rate))
|
||||||
cleanedData.video_stream = cleaned_streams.find(s => s.type === 'video')
|
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) => {
|
return new Promise((resolve) => {
|
||||||
Ffmpeg.ffprobe(filepath, ['-show_chapters'], (err, raw) => {
|
Ffmpeg.ffprobe(filepath, ['-show_chapters'], (err, raw) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
resolve(null)
|
resolve(null)
|
||||||
} else {
|
} else {
|
||||||
resolve(parseProbeData(raw))
|
resolve(parseProbeData(raw, verbose))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user