mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-04 21:20:09 +01:00
Cleaning up server code
Doing some literal cleaning
This commit is contained in:
parent
f31700f668
commit
8754f0c25f
@ -3,7 +3,7 @@ const Logger = require('../../Logger')
|
|||||||
const BookMetadata = require('../metadata/BookMetadata')
|
const BookMetadata = require('../metadata/BookMetadata')
|
||||||
const { areEquivalent, copyValue } = require('../../utils/index')
|
const { areEquivalent, copyValue } = require('../../utils/index')
|
||||||
const { parseOpfMetadataXML } = require('../../utils/parsers/parseOpfMetadata')
|
const { parseOpfMetadataXML } = require('../../utils/parsers/parseOpfMetadata')
|
||||||
const { getOverdriveMediaMarkersFromFiles, parseOverdriveMediaMarkers } = require('../../utils/parsers/parseOverdriveMediaMarkers')
|
const { overdriveMediaMarkersExist, parseOverdriveMediaMarkersAsChapters } = require('../../utils/parsers/parseOverdriveMediaMarkers')
|
||||||
const abmetadataGenerator = require('../../utils/abmetadataGenerator')
|
const abmetadataGenerator = require('../../utils/abmetadataGenerator')
|
||||||
const { readTextFile } = require('../../utils/fileUtils')
|
const { readTextFile } = require('../../utils/fileUtils')
|
||||||
const AudioFile = require('../files/AudioFile')
|
const AudioFile = require('../files/AudioFile')
|
||||||
@ -403,63 +403,60 @@ class Book {
|
|||||||
// If 1 audio file without chapters, then no chapters will be set
|
// If 1 audio file without chapters, then no chapters will be set
|
||||||
var includedAudioFiles = this.audioFiles.filter(af => !af.exclude)
|
var includedAudioFiles = this.audioFiles.filter(af => !af.exclude)
|
||||||
|
|
||||||
var overdriveMediaMarkers = getOverdriveMediaMarkersFromFiles(includedAudioFiles)
|
// If overdrive media markers are present and preferred, use those instead
|
||||||
|
if (preferOverdriveMediaMarker && overdriveMediaMarkersExist(includedAudioFiles)) {
|
||||||
|
Logger.info('[Book] Overdrive Media Markers and preference found! Using these for chapter definitions')
|
||||||
|
return this.chapters = parseOverdriveMediaMarkersAsChapters(includedAudioFiles)
|
||||||
|
}
|
||||||
|
|
||||||
// If preferOverdriveMediaMarker is set, try and use that first
|
if (includedAudioFiles.length === 1) {
|
||||||
// fallback to non-overdrive chapters if there are no Overdrive Media Markers available
|
// 1 audio file with chapters
|
||||||
if (preferOverdriveMediaMarker && (overdriveMediaMarkers.length > 0)) {
|
if (includedAudioFiles[0].chapters) {
|
||||||
Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`)
|
this.chapters = includedAudioFiles[0].chapters.map(c => ({ ...c }))
|
||||||
this.chapters = parseOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles)
|
|
||||||
} else {
|
|
||||||
if (includedAudioFiles.length === 1) {
|
|
||||||
// 1 audio file with chapters
|
|
||||||
if (includedAudioFiles[0].chapters) {
|
|
||||||
this.chapters = includedAudioFiles[0].chapters.map(c => ({ ...c }))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.chapters = []
|
|
||||||
var currChapterId = 0
|
|
||||||
var currStartTime = 0
|
|
||||||
includedAudioFiles.forEach((file) => {
|
|
||||||
//console.log(`audiofile MetaTags Overdrive: ${JSON.stringify(file.metaTags.tagOverdriveMediaMarker)}}`)
|
|
||||||
// If audio file has chapters use chapters
|
|
||||||
if (file.chapters && file.chapters.length) {
|
|
||||||
file.chapters.forEach((chapter) => {
|
|
||||||
if (chapter.start > this.duration) {
|
|
||||||
Logger.warn(`[Book] Invalid chapter start time > duration`)
|
|
||||||
} else {
|
|
||||||
var chapterAlreadyExists = this.chapters.find(ch => ch.start === chapter.start)
|
|
||||||
if (!chapterAlreadyExists) {
|
|
||||||
var chapterDuration = chapter.end - chapter.start
|
|
||||||
if (chapterDuration > 0) {
|
|
||||||
var title = `Chapter ${currChapterId}`
|
|
||||||
if (chapter.title) {
|
|
||||||
title += ` (${chapter.title})`
|
|
||||||
}
|
|
||||||
var endTime = Math.min(this.duration, currStartTime + chapterDuration)
|
|
||||||
this.chapters.push({
|
|
||||||
id: currChapterId++,
|
|
||||||
start: currStartTime,
|
|
||||||
end: endTime,
|
|
||||||
title
|
|
||||||
})
|
|
||||||
currStartTime += chapterDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (file.duration) {
|
|
||||||
// Otherwise just use track has chapter
|
|
||||||
this.chapters.push({
|
|
||||||
id: currChapterId++,
|
|
||||||
start: currStartTime,
|
|
||||||
end: currStartTime + file.duration,
|
|
||||||
title: file.metadata.filename ? Path.basename(file.metadata.filename, Path.extname(file.metadata.filename)) : `Chapter ${currChapterId}`
|
|
||||||
})
|
|
||||||
currStartTime += file.duration
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.chapters = []
|
||||||
|
var currChapterId = 0
|
||||||
|
var currStartTime = 0
|
||||||
|
includedAudioFiles.forEach((file) => {
|
||||||
|
//console.log(`audiofile MetaTags Overdrive: ${JSON.stringify(file.metaTags.tagOverdriveMediaMarker)}}`)
|
||||||
|
// If audio file has chapters use chapters
|
||||||
|
if (file.chapters && file.chapters.length) {
|
||||||
|
file.chapters.forEach((chapter) => {
|
||||||
|
if (chapter.start > this.duration) {
|
||||||
|
Logger.warn(`[Book] Invalid chapter start time > duration`)
|
||||||
|
} else {
|
||||||
|
var chapterAlreadyExists = this.chapters.find(ch => ch.start === chapter.start)
|
||||||
|
if (!chapterAlreadyExists) {
|
||||||
|
var chapterDuration = chapter.end - chapter.start
|
||||||
|
if (chapterDuration > 0) {
|
||||||
|
var title = `Chapter ${currChapterId}`
|
||||||
|
if (chapter.title) {
|
||||||
|
title += ` (${chapter.title})`
|
||||||
|
}
|
||||||
|
var endTime = Math.min(this.duration, currStartTime + chapterDuration)
|
||||||
|
this.chapters.push({
|
||||||
|
id: currChapterId++,
|
||||||
|
start: currStartTime,
|
||||||
|
end: endTime,
|
||||||
|
title
|
||||||
|
})
|
||||||
|
currStartTime += chapterDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (file.duration) {
|
||||||
|
// Otherwise just use track has chapter
|
||||||
|
this.chapters.push({
|
||||||
|
id: currChapterId++,
|
||||||
|
start: currStartTime,
|
||||||
|
end: currStartTime + file.duration,
|
||||||
|
title: file.metadata.filename ? Path.basename(file.metadata.filename, Path.extname(file.metadata.filename)) : `Chapter ${currChapterId}`
|
||||||
|
})
|
||||||
|
currStartTime += file.duration
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,53 +1,16 @@
|
|||||||
const Logger = require('../../Logger')
|
const Logger = require('../../Logger')
|
||||||
|
|
||||||
// given an array of audioFiles, return an array of unparsed MediaMarkers
|
// given a list of audio files, extract all of the Overdrive Media Markers metaTags, and return an array of them as XML
|
||||||
module.exports.getOverdriveMediaMarkersFromFiles = (audioFiles) => {
|
function overdriveMediaMarkers(includedAudioFiles) {
|
||||||
var markers = audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || []
|
var markers = includedAudioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || []
|
||||||
return markers
|
return markers
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.parseOverdriveMediaMarkers = (overdriveMediaMarkers, includedAudioFiles) => {
|
// given the array of Overdrive Media Markers from generateOverdriveMediaMarkers()
|
||||||
|
// parse and clean them in to something a bit more usable
|
||||||
|
function cleanOverdriveMediaMarkers(overdriveMediaMarkers) {
|
||||||
var parseString = require('xml2js').parseString; // function to convert xml to JSON
|
var parseString = require('xml2js').parseString; // function to convert xml to JSON
|
||||||
|
var parsedOverdriveMediaMarkers = []
|
||||||
var parsedOverdriveMediaMarkers = [] // an array of objects. each object being a chapter with a name and time key. the values are arrays of strings
|
|
||||||
|
|
||||||
overdriveMediaMarkers.forEach(function (item, index) {
|
|
||||||
var parsed_result
|
|
||||||
parseString(item, function (err, result) {
|
|
||||||
// result.Markers.Marker is the result of parsing the XML for the MediaMarker tags for the MP3 file (Part##.mp3)
|
|
||||||
// it is shaped like this:
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// "Name": [
|
|
||||||
// "Chapter 1: "
|
|
||||||
// ],
|
|
||||||
// "Time": [
|
|
||||||
// "0:00.000"
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "Name": [
|
|
||||||
// "Chapter 2: "
|
|
||||||
// ],
|
|
||||||
// "Time": [
|
|
||||||
// "15:51.000"
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
|
|
||||||
parsed_result = result.Markers.Marker
|
|
||||||
|
|
||||||
// The values for Name and Time in parsed_results are returned as Arrays from parseString
|
|
||||||
// update them to be strings
|
|
||||||
parsed_result.forEach((item, index) => {
|
|
||||||
Object.keys(item).forEach(key => {
|
|
||||||
item[key] = item[key].toString()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
parsedOverdriveMediaMarkers.push(parsed_result)
|
|
||||||
})
|
|
||||||
|
|
||||||
// go from an array of arrays of objects to an array of objects
|
// go from an array of arrays of objects to an array of objects
|
||||||
// end result looks like:
|
// end result looks like:
|
||||||
@ -62,40 +25,89 @@ module.exports.parseOverdriveMediaMarkers = (overdriveMediaMarkers, includedAudi
|
|||||||
// },
|
// },
|
||||||
// { redacted }
|
// { redacted }
|
||||||
// ]
|
// ]
|
||||||
parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers
|
overdriveMediaMarkers.forEach(function (item, index) {
|
||||||
|
var parsed_result
|
||||||
|
parseString(item, function (err, result) {
|
||||||
|
// result.Markers.Marker is the result of parsing the XML for the MediaMarker tags for the MP3 file (Part##.mp3)
|
||||||
|
// it is shaped like this:
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "Name": [
|
||||||
|
// "Chapter 1: "
|
||||||
|
// ],
|
||||||
|
// "Time": [
|
||||||
|
// "0:00.000"
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "Name": [
|
||||||
|
// "Chapter 2: "
|
||||||
|
// ],
|
||||||
|
// "Time": [
|
||||||
|
// "15:51.000"
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
var index = 0
|
parsed_result = result.Markers.Marker
|
||||||
|
|
||||||
var time = 0.0
|
|
||||||
|
|
||||||
|
|
||||||
|
// The values for Name and Time in parsed_results are returned as Arrays from parseString
|
||||||
|
// update them to be strings
|
||||||
|
parsed_result.forEach((item, index) => {
|
||||||
|
Object.keys(item).forEach(key => {
|
||||||
|
item[key] = item[key].toString()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
parsedOverdriveMediaMarkers.push(parsed_result)
|
||||||
|
})
|
||||||
|
|
||||||
|
return parsedOverdriveMediaMarkers
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function that actually generates the Chapters object that we update ABS with
|
||||||
|
function generateParsedChapters(includedAudioFiles, cleanedOverdriveMediaMarkers) {
|
||||||
// actually generate the chapter object
|
// actually generate the chapter object
|
||||||
// logic ported over from benonymity's OverdriveChapterizer:
|
// logic ported over from benonymity's OverdriveChapterizer:
|
||||||
// https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py
|
// https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py
|
||||||
var length = 0.0
|
var length = 0.0
|
||||||
var newOChapters = []
|
var index = 0
|
||||||
|
var time = 0.0
|
||||||
|
var newChapters = []
|
||||||
const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/
|
const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/
|
||||||
includedAudioFiles.forEach((track, track_index) => {
|
includedAudioFiles.forEach((track, track_index) => {
|
||||||
parsedOverdriveMediaMarkers[track_index].forEach((chapter) => {
|
cleanedOverdriveMediaMarkers[track_index].forEach((chapter) => {
|
||||||
Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}!`)
|
Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}...`)
|
||||||
if (weirdChapterFilterRegex.test(chapter.Name)) {
|
if (weirdChapterFilterRegex.test(chapter.Name)) {
|
||||||
Logger.debug(`[parseOverdriveMediaMarkers] That shit weird yo`)
|
Logger.debug(`[parseOverdriveMediaMarkers] Regex matched. Skipping ${chapter.Name}!`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time = chapter.Time.split(":")
|
time = chapter.Time.split(":")
|
||||||
time = length + parseFloat(time[0]) * 60 + parseFloat(time[1])
|
time = length + parseFloat(time[0]) * 60 + parseFloat(time[1])
|
||||||
newOChapters.push(
|
newChapters.push(
|
||||||
{
|
{
|
||||||
id: index++,
|
id: index++,
|
||||||
start: time,
|
start: time,
|
||||||
end: length,
|
end: length,
|
||||||
title: chapter.Name
|
title: chapter.Name
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
length += track.duration
|
length += track.duration
|
||||||
})
|
})
|
||||||
|
|
||||||
Logger.debug(`[parseOverdriveMediaMarkers] newOChapters: ${JSON.stringify(newOChapters)}`)
|
return newChapters
|
||||||
return newOChapters
|
}
|
||||||
}
|
|
||||||
|
module.exports.overdriveMediaMarkersExist = (includedAudioFiles) => {
|
||||||
|
return overdriveMediaMarkers(includedAudioFiles).length > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.parseOverdriveMediaMarkersAsChapters = (includedAudioFiles) => {
|
||||||
|
Logger.info('[parseOverdriveMediaMarkers] Parsing of Overdrive Media Markers started')
|
||||||
|
var cleanedOverdriveMediaMarkers = cleanOverdriveMediaMarkers(overdriveMediaMarkers(includedAudioFiles))
|
||||||
|
var parsedChapters = generateParsedChapters(includedAudioFiles, cleanedOverdriveMediaMarkers)
|
||||||
|
|
||||||
|
return parsedChapters
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user