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:
Mark Cooper 2021-09-30 18:52:32 -05:00
parent dc18eb408e
commit d6cab8e591
28 changed files with 684 additions and 113 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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) => {

View file

@ -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

View file

@ -137,7 +137,6 @@ function parseChapters(chapters) {
function parseTags(format) {
if (!format.tags) {
Logger.debug('No Tags')
return {}
}
// Logger.debug('Tags', format.tags)

View file

@ -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) => {