mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-04 10:14:36 +02:00
logLevel as server setting, logger config page, re-scan audiobook option, fix embedded cover extraction, flac and mobi support, fix series bookshelf not wrapping
This commit is contained in:
parent
dc18eb408e
commit
d6cab8e591
28 changed files with 684 additions and 113 deletions
|
@ -83,6 +83,9 @@ function getTrackNumberFromFilename(title, author, series, publishYear, filename
|
|||
if (series) partbasename = partbasename.replace(series, '')
|
||||
if (publishYear) partbasename = partbasename.replace(publishYear)
|
||||
|
||||
// Remove eg. "disc 1" from path
|
||||
partbasename = partbasename.replace(/ disc \d\d? /i, '')
|
||||
|
||||
var numbersinpath = partbasename.match(/\d+/g)
|
||||
if (!numbersinpath) return null
|
||||
|
||||
|
@ -95,9 +98,11 @@ async function scanAudioFiles(audiobook, newAudioFiles) {
|
|||
Logger.error('[AudioFileScanner] Scan Audio Files no new files', audiobook.title)
|
||||
return
|
||||
}
|
||||
|
||||
var tracks = []
|
||||
var numDuplicateTracks = 0
|
||||
var numInvalidTracks = 0
|
||||
|
||||
for (let i = 0; i < newAudioFiles.length; i++) {
|
||||
var audioFile = newAudioFiles[i]
|
||||
var scanData = await scan(audioFile.fullPath)
|
||||
|
@ -109,6 +114,7 @@ async function scanAudioFiles(audiobook, newAudioFiles) {
|
|||
|
||||
var trackNumFromMeta = getTrackNumberFromMeta(scanData)
|
||||
var book = audiobook.book || {}
|
||||
|
||||
var trackNumFromFilename = getTrackNumberFromFilename(book.title, book.author, book.series, book.publishYear, audioFile.filename)
|
||||
|
||||
var audioFileObj = {
|
||||
|
@ -182,4 +188,47 @@ async function scanAudioFiles(audiobook, newAudioFiles) {
|
|||
audiobook.tracks.sort((a, b) => a.index - b.index)
|
||||
}
|
||||
}
|
||||
module.exports.scanAudioFiles = scanAudioFiles
|
||||
module.exports.scanAudioFiles = scanAudioFiles
|
||||
|
||||
|
||||
async function rescanAudioFiles(audiobook) {
|
||||
|
||||
var audioFiles = audiobook.audioFiles
|
||||
var updates = 0
|
||||
|
||||
for (let i = 0; i < audioFiles.length; i++) {
|
||||
var audioFile = audioFiles[i]
|
||||
var scanData = await scan(audioFile.fullPath)
|
||||
if (!scanData || scanData.error) {
|
||||
Logger.error('[AudioFileScanner] Scan failed for', audioFile.path)
|
||||
// audiobook.invalidAudioFiles.push(parts[i])
|
||||
continue;
|
||||
}
|
||||
var hasUpdates = audioFile.updateMetadata(scanData)
|
||||
if (hasUpdates) {
|
||||
// Sync audio track with audio file
|
||||
var matchingAudioTrack = audiobook.tracks.find(t => t.ino === audioFile.ino)
|
||||
if (matchingAudioTrack) {
|
||||
matchingAudioTrack.syncMetadata(audioFile)
|
||||
} else if (!audioFile.exclude) { // If audio file is not excluded then it should have an audio track
|
||||
|
||||
// Fallback to checking path
|
||||
matchingAudioTrack = audiobook.tracks.find(t => t.path === audioFile.path)
|
||||
if (matchingAudioTrack) {
|
||||
Logger.warn(`[AudioFileScanner] Audio File mismatch ino with audio track "${audioFile.filename}"`)
|
||||
matchingAudioTrack.ino = audioFile.ino
|
||||
matchingAudioTrack.syncMetadata(audioFile)
|
||||
} else {
|
||||
Logger.error(`[AudioFileScanner] Audio File has no matching Track ${audioFile.filename} for "${audiobook.title}"`)
|
||||
|
||||
// Exclude audio file to prevent further errors
|
||||
// audioFile.exclude = true
|
||||
}
|
||||
}
|
||||
updates++
|
||||
}
|
||||
}
|
||||
|
||||
return updates
|
||||
}
|
||||
module.exports.rescanAudioFiles = rescanAudioFiles
|
|
@ -9,4 +9,14 @@ module.exports.ScanResult = {
|
|||
module.exports.CoverDestination = {
|
||||
METADATA: 0,
|
||||
AUDIOBOOK: 1
|
||||
}
|
||||
|
||||
module.exports.LogLevel = {
|
||||
TRACE: 0,
|
||||
DEBUG: 1,
|
||||
INFO: 2,
|
||||
WARN: 3,
|
||||
ERROR: 4,
|
||||
FATAL: 5,
|
||||
NOTE: 6
|
||||
}
|
|
@ -75,7 +75,7 @@ async function extractCoverArt(filepath, outputpath) {
|
|||
|
||||
return new Promise((resolve) => {
|
||||
var ffmpeg = Ffmpeg(filepath)
|
||||
ffmpeg.addOption(['-map 0:v'])
|
||||
ffmpeg.addOption(['-map 0:v', '-frames:v 1'])
|
||||
ffmpeg.output(outputpath)
|
||||
|
||||
ffmpeg.on('start', (cmd) => {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const fs = require('fs-extra')
|
||||
|
||||
function getPlaylistStr(segmentName, duration, segmentLength) {
|
||||
function getPlaylistStr(segmentName, duration, segmentLength, hlsSegmentType) {
|
||||
var ext = hlsSegmentType === 'fmp4' ? 'm4s' : 'ts'
|
||||
|
||||
var lines = [
|
||||
'#EXTM3U',
|
||||
'#EXT-X-VERSION:3',
|
||||
|
@ -9,22 +11,25 @@ function getPlaylistStr(segmentName, duration, segmentLength) {
|
|||
'#EXT-X-MEDIA-SEQUENCE:0',
|
||||
'#EXT-X-PLAYLIST-TYPE:VOD'
|
||||
]
|
||||
if (hlsSegmentType === 'fmp4') {
|
||||
lines.push('#EXT-X-MAP:URI="init.mp4"')
|
||||
}
|
||||
var numSegments = Math.floor(duration / segmentLength)
|
||||
var lastSegment = duration - (numSegments * segmentLength)
|
||||
for (let i = 0; i < numSegments; i++) {
|
||||
lines.push(`#EXTINF:6,`)
|
||||
lines.push(`${segmentName}-${i}.ts`)
|
||||
lines.push(`${segmentName}-${i}.${ext}`)
|
||||
}
|
||||
if (lastSegment > 0) {
|
||||
lines.push(`#EXTINF:${lastSegment},`)
|
||||
lines.push(`${segmentName}-${numSegments}.ts`)
|
||||
lines.push(`${segmentName}-${numSegments}.${ext}`)
|
||||
}
|
||||
lines.push('#EXT-X-ENDLIST')
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
function generatePlaylist(outputPath, segmentName, duration, segmentLength) {
|
||||
var playlistStr = getPlaylistStr(segmentName, duration, segmentLength)
|
||||
function generatePlaylist(outputPath, segmentName, duration, segmentLength, hlsSegmentType) {
|
||||
var playlistStr = getPlaylistStr(segmentName, duration, segmentLength, hlsSegmentType)
|
||||
return fs.writeFile(outputPath, playlistStr)
|
||||
}
|
||||
module.exports = generatePlaylist
|
|
@ -137,7 +137,6 @@ function parseChapters(chapters) {
|
|||
|
||||
function parseTags(format) {
|
||||
if (!format.tags) {
|
||||
Logger.debug('No Tags')
|
||||
return {}
|
||||
}
|
||||
// Logger.debug('Tags', format.tags)
|
||||
|
|
|
@ -3,10 +3,10 @@ const dir = require('node-dir')
|
|||
const Logger = require('../Logger')
|
||||
const { getIno } = require('./index')
|
||||
|
||||
const AUDIO_FORMATS = ['m4b', 'mp3', 'm4a']
|
||||
const AUDIO_FORMATS = ['m4b', 'mp3', 'm4a', 'flac']
|
||||
const INFO_FORMATS = ['nfo']
|
||||
const IMAGE_FORMATS = ['png', 'jpg', 'jpeg', 'webp']
|
||||
const EBOOK_FORMATS = ['epub', 'pdf']
|
||||
const EBOOK_FORMATS = ['epub', 'pdf', 'mobi']
|
||||
|
||||
function getPaths(path) {
|
||||
return new Promise((resolve) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue