From fc614b983362f713c41c4b64656bd41607a82303 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 02:00:07 -0700 Subject: [PATCH 01/21] Add support for overdrive media marker file tag This commit adds serverside support for grabbing the overdrive_media_marker file tag that exists on mp3 files from overdrive --- server/objects/metadata/AudioMetaTags.js | 6 +++++- server/objects/metadata/BookMetadata.js | 4 ++++ server/utils/prober.js | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/objects/metadata/AudioMetaTags.js b/server/objects/metadata/AudioMetaTags.js index 65ac0d9c..13bb2a83 100644 --- a/server/objects/metadata/AudioMetaTags.js +++ b/server/objects/metadata/AudioMetaTags.js @@ -20,6 +20,7 @@ class AudioMetaTags { this.tagIsbn = null this.tagLanguage = null this.tagASIN = null + this.tagOverdriveMediaMarker = null if (metadata) { this.construct(metadata) @@ -58,6 +59,7 @@ class AudioMetaTags { this.tagIsbn = metadata.tagIsbn || null this.tagLanguage = metadata.tagLanguage || null this.tagASIN = metadata.tagASIN || null + this.tagOverdriveMediaMarker = metadata.tagOverdriveMediaMarker || null } // Data parsed in prober.js @@ -82,6 +84,7 @@ class AudioMetaTags { this.tagIsbn = payload.file_tag_isbn || null this.tagLanguage = payload.file_tag_language || null this.tagASIN = payload.file_tag_asin || null + this.tagOverdriveMediaMarker = payload.file_tag_overdrive_media_marker || null } updateData(payload) { @@ -105,7 +108,8 @@ class AudioMetaTags { tagEncodedBy: payload.file_tag_encodedby || null, tagIsbn: payload.file_tag_isbn || null, tagLanguage: payload.file_tag_language || null, - tagASIN: payload.file_tag_asin || null + tagASIN: payload.file_tag_asin || null, + tagOverdriveMediaMarker: payload.file_tag_overdrive_media_marker || null, } var hasUpdates = false diff --git a/server/objects/metadata/BookMetadata.js b/server/objects/metadata/BookMetadata.js index 6bcf38bf..4cedd1cb 100644 --- a/server/objects/metadata/BookMetadata.js +++ b/server/objects/metadata/BookMetadata.js @@ -262,6 +262,10 @@ class BookMetadata { { tag: 'tagASIN', key: 'asin' + }, + { + tag: 'tagOverdriveMediaMarker', + key: 'overdriveMediaMarker' } ] diff --git a/server/utils/prober.js b/server/utils/prober.js index d7d60c2f..890899b8 100644 --- a/server/utils/prober.js +++ b/server/utils/prober.js @@ -192,6 +192,7 @@ function parseTags(format, verbose) { file_tag_movement: tryGrabTags(format, 'movement', 'mvin'), file_tag_genre1: tryGrabTags(format, 'tmp_genre1', 'genre1'), file_tag_genre2: tryGrabTags(format, 'tmp_genre2', 'genre2'), + file_tag_overdrive_media_marker: tryGrabTags(format, 'OverDrive MediaMarkers'), } for (const key in tags) { if (!tags[key]) { From 27e6b9ce0d7171f68cae9f94f76479a3eeef122f Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 02:01:37 -0700 Subject: [PATCH 02/21] DRAFT client support for overdrive media markers Initial client side support. Still a good amount to do. Specifically around actually parsing out all of the media markers, and generating a single chapter object that can be applied --- client/pages/audiobook/_id/chapters.vue | 100 +++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index d5351dd5..73f8c537 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -22,6 +22,16 @@
+
+
+

Overdrive Media Markers Found! Would you like to generate chapter data from them?

+
+ Yes + +
+
+
+
Start
@@ -85,6 +95,7 @@ check
+
@@ -131,6 +142,45 @@ + + + +
+
+ + Find +
+
+

Duration found: {{ chapterData.runtimeLengthSec }}

+
+

Chapter data invalid duration
Your media duration is shorter than duration found

+
+ +
+
Start
+
Title
+
+
+
+
+

{{ $secondsToTimestamp(chapter.startOffsetSec) }}

+
+
+

{{ chapter.title }}

+
+
+
+
+
+ Apply Chapters +
+
+
+
@@ -168,6 +218,7 @@ export default { asinInput: null, findingChapters: false, showFindChaptersModal: false, + showImportOverdriveMediaMarkersModal: false, chapterData: null } }, @@ -190,13 +241,19 @@ export default { mediaDuration() { return this.media.duration }, + overdriveMediaMarkersExist() { + return (this.overdriveMediaMarkers?.length > 0 ? true : false ) || false + }, + overdriveMediaMarkers() { + return this.audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined) || [] + }, chapters() { return this.media.chapters || [] }, tracks() { return this.media.tracks || [] }, - audioFiles() { + audioFiles() { return this.media.audioFiles || [] }, audioTracks() { @@ -207,6 +264,13 @@ export default { } }, methods: { + checkForOverdriveMediaMarkers() { + if (this.overdriveMediaMarkersExist) { + this.$toast.success('Your book has overdrive media markers!') + } else { + this.$toast.error('Your book DOES NOT have overdrive media markers!') + } + }, editItem() { this.$store.commit('showEditModal', this.libraryItem) }, @@ -392,7 +456,7 @@ export default { this.$toast.error(data.error) this.showFindChaptersModal = false } else { - console.log('Chapter data', data) + console.log('Chapter data', JSON.stringify(data)) this.chapterData = data } }) @@ -402,9 +466,41 @@ export default { this.$toast.error('Failed to find chapters') this.showFindChaptersModal = false }) + }, + // overdrive + generateChaptersFromOverdriveMediaMarkers() { + var parseString = require('xml2js').parseString; + var xml = this.overdriveMediaMarkers[0] + var parsedXML = {} + parseString(xml, function (err, result) { + parsedXML = result + }); + + var index = 0 + var newOChapters = parsedXML.Markers.Marker.map((marker) => { + return { + id: index++, + start: marker.Time[0], + end: 0, + title: marker.Name[0] + } + }) + console.log(newOChapters) + //console.log(this.overdriveMediaMarkers[0]) + // console.log(JSON.stringify(x)) + //console.log(parseString(this.overdriveMediaMarkers[0])) + // { + // id:, + // start: + // end: + // title: + // } + this.overdriveMediaMarkers } }, mounted() { + this.checkForOverdriveMediaMarkers() + var dismissed = false this.asinInput = this.mediaMetadata.asin || null this.newChapters = this.chapters.map((c) => ({ ...c })) if (!this.newChapters.length) { From 430fbf5e46fc3db696d7aa45d6f37e47dced8f87 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 09:34:22 -0700 Subject: [PATCH 03/21] Parse out mediamarkers from all files This commit updates the logic in generateChaptersFromOverdriveMediaMarkers to create a single array of objects that holds all of the clean MediaMarker data. it still needs to be conveted to the NewChapters format. I should also rename this function to "cleanChaptersFromOMM", but I"ll do that later --- client/pages/audiobook/_id/chapters.vue | 86 ++++++++++++++++++------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index 73f8c537..265be032 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -437,6 +437,7 @@ export default { title: chap.title } }) + console.log(`newChapters - ${JSON.stringify(this.newChapters)}`) this.showFindChaptersModal = false this.chapterData = null }, @@ -469,33 +470,68 @@ export default { }, // overdrive generateChaptersFromOverdriveMediaMarkers() { - var parseString = require('xml2js').parseString; - var xml = this.overdriveMediaMarkers[0] - var parsedXML = {} - parseString(xml, function (err, result) { - parsedXML = result - }); + var parseString = require('xml2js').parseString; // function to convert xml to JSON + var overdriveMediaMarkers = this.overdriveMediaMarkers // an array of XML. 1 Part.mp3 to 1 array index. Each index holds 1 XML that holds multiple chapters + //console.log(overdriveMediaMarkers) + + var parsedOverdriveMediaMarkers = [] // an array of objects. each object being a chapter with a name and time key. the values are arrays of strings - var index = 0 - var newOChapters = parsedXML.Markers.Marker.map((marker) => { - return { - id: index++, - start: marker.Time[0], - end: 0, - title: marker.Name[0] - } + overdriveMediaMarkers.forEach(function (item, index) { + var parsed_result + var holder + 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 + // update them to be strings + parsed_result.forEach((item, index) => { + Object.keys(item).forEach(key => { + item[key] = item[key].toString() + }) + }) + }) + + parsedOverdriveMediaMarkers.push(parsed_result) }) - console.log(newOChapters) - //console.log(this.overdriveMediaMarkers[0]) - // console.log(JSON.stringify(x)) - //console.log(parseString(this.overdriveMediaMarkers[0])) - // { - // id:, - // start: - // end: - // title: - // } - this.overdriveMediaMarkers + + console.log(parsedOverdriveMediaMarkers.flat()) + + // go from an array of arrays of objects to an array of objects + parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers.flat() + + // var index = 0 + // var newOChapters = parsedXML.Markers.Marker.map((marker) => { + // return { + // id: index++, + // start: marker.Time[0], + // end: 0, + // title: marker.Name[0] + // } + // }) + // console.log(newOChapters) + + // this.overdriveMediaMarkers } }, mounted() { From e01748eb2f9ff071d9001d3dad60ba6efa76c627 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 10:57:17 -0700 Subject: [PATCH 04/21] Full support for generating/applying chapter data This commit adds the rest of the support for actually being able to use Overdrive MediaMarkers. Shoutout to benonymity's project OverdriveChapterize, where I was able to port over the logic to actually do the timestamp conversions https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py I still need to do a lot of cleanup of the actual code, and finish the UI. --- client/pages/audiobook/_id/chapters.vue | 58 +++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index 265be032..781d70ad 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -472,13 +472,11 @@ export default { generateChaptersFromOverdriveMediaMarkers() { var parseString = require('xml2js').parseString; // function to convert xml to JSON var overdriveMediaMarkers = this.overdriveMediaMarkers // an array of XML. 1 Part.mp3 to 1 array index. Each index holds 1 XML that holds multiple chapters - //console.log(overdriveMediaMarkers) 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 - var holder 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: @@ -503,7 +501,7 @@ export default { parsed_result = result.Markers.Marker - // The values for Name and Time in parsed results are returned as Arrays + // 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 => { @@ -515,25 +513,51 @@ export default { parsedOverdriveMediaMarkers.push(parsed_result) }) - console.log(parsedOverdriveMediaMarkers.flat()) - // go from an array of arrays of objects to an array of objects - parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers.flat() + // end result looks like: + // [ + // { + // "Name": "Chapter 1: The Worst Birthday", + // "Time": "0:00.000" + // }, + // { + // "Name": "Chapter 2: Dobby's Warning", + // "Time": "15:51.000" + // }, + // { redacted } + // ] + parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers - // var index = 0 - // var newOChapters = parsedXML.Markers.Marker.map((marker) => { - // return { - // id: index++, - // start: marker.Time[0], - // end: 0, - // title: marker.Name[0] - // } - // }) - // console.log(newOChapters) + var index = 0 + + var time = 0.0 + - // this.overdriveMediaMarkers + // actually generate the chapter object + // logic ported over from benonymity's OverdriveChapterizer: + // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py + var length = 0.0 + var newOChapters = [] + this.audioTracks.forEach((track, track_index) => { + parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { + time = chapter.Time.split(":") + time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) + newOChapters.push( + { + id: index++, + start: time, + end: length, + title: chapter.Name + } + ) + }) + length += track.duration + }) + + this.newChapters = newOChapters } }, + mounted() { this.checkForOverdriveMediaMarkers() var dismissed = false From b90934a72aced4fb20c8e606ec1f124c26a9986a Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 11:06:19 -0700 Subject: [PATCH 05/21] remove unused modal --- client/pages/audiobook/_id/chapters.vue | 39 ------------------------- 1 file changed, 39 deletions(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index 781d70ad..ef4d60c0 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -142,45 +142,6 @@
- - - -
-
- - Find -
-
-

Duration found: {{ chapterData.runtimeLengthSec }}

-
-

Chapter data invalid duration
Your media duration is shorter than duration found

-
- -
-
Start
-
Title
-
-
-
-
-

{{ $secondsToTimestamp(chapter.startOffsetSec) }}

-
-
-

{{ chapter.title }}

-
-
-
-
-
- Apply Chapters -
-
-
-
From effc63755b5191dd6a8f7dd3151648f928fb6b13 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 11:07:49 -0700 Subject: [PATCH 06/21] remove unused console.log --- client/pages/audiobook/_id/chapters.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index ef4d60c0..519d0f14 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -398,7 +398,6 @@ export default { title: chap.title } }) - console.log(`newChapters - ${JSON.stringify(this.newChapters)}`) this.showFindChaptersModal = false this.chapterData = null }, From b3d9323f66e75583e90d0bd44bf3d9474d82a5b7 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 23:17:22 -0700 Subject: [PATCH 07/21] Initial commit for server side approach This is the first commit for bringing this over to the server side. It works! Right now it fails if the autoscanner or or the manual individual book scanner try to do it's thing. I'll need to update those --- server/controllers/PodcastController.js | 2 +- server/objects/mediaTypes/Book.js | 187 +++++++++++++++++----- server/objects/settings/ServerSettings.js | 3 + server/scanner/MediaFileScanner.js | 14 +- server/scanner/ScanOptions.js | 5 +- server/scanner/Scanner.js | 6 + 6 files changed, 175 insertions(+), 42 deletions(-) diff --git a/server/controllers/PodcastController.js b/server/controllers/PodcastController.js index 81029c95..9d1aa2c8 100644 --- a/server/controllers/PodcastController.js +++ b/server/controllers/PodcastController.js @@ -103,7 +103,7 @@ class PodcastController { Logger.error('Invalid podcast feed request response') return res.status(500).send('Bad response from feed request') } - Logger.debug(`[PdocastController] Podcast feed size ${(data.data.length / 1024 / 1024).toFixed(2)}MB`) + Logger.debug(`[PodcastController] Podcast feed size ${(data.data.length / 1024 / 1024).toFixed(2)}MB`) var payload = await parsePodcastRssFeedXml(data.data, false, includeRaw) if (!payload) { return res.status(500).send('Invalid podcast RSS feed') diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index 6f0f4a1d..d8ee7528 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -360,10 +360,12 @@ class Book { this.rebuildTracks() } - rebuildTracks() { + rebuildTracks(preferOverdriveMediaMarker = false) { + Logger.debug(`[Book] we are rebuilding the tracks!`) + Logger.debug(`[Book] preferOverdriveMediaMarker: ${preferOverdriveMediaMarker}`) this.audioFiles.sort((a, b) => a.index - b.index) this.missingParts = [] - this.setChapters() + this.setChapters(preferOverdriveMediaMarker) this.checkUpdateMissingTracks() } @@ -395,7 +397,103 @@ class Book { return wasUpdated } - setChapters() { + generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) { + var parseString = require('xml2js').parseString; // function to convert xml to JSON + + 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 + // end result looks like: + // [ + // { + // "Name": "Chapter 1: The Worst Birthday", + // "Time": "0:00.000" + // }, + // { + // "Name": "Chapter 2: Dobby's Warning", + // "Time": "15:51.000" + // }, + // { redacted } + // ] + parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers + + var index = 0 + + var time = 0.0 + + + // actually generate the chapter object + // logic ported over from benonymity's OverdriveChapterizer: + // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py + var length = 0.0 + var newOChapters = [] + const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ + includedAudioFiles.forEach((track, track_index) => { + parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { + Logger.debug(`[Book] Attempting regex check for ${chapter.Name}!`) + if (weirdChapterFilterRegex.test(chapter.Name)) { + Logger.debug(`[Book] That shit weird yo`) + return + } + time = chapter.Time.split(":") + time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) + newOChapters.push( + { + id: index++, + start: time, + end: length, + title: chapter.Name + } + ) + }) + length += track.duration + }) + + Logger.debug(`[Book] newOChapters: ${JSON.stringify(newOChapters)}`) + return newOChapters + } + + + setChapters(preferOverdriveMediaMarker = false) { + Logger.debug('[Book] inside setChapters!') // If 1 audio file without chapters, then no chapters will be set var includedAudioFiles = this.audioFiles.filter(af => !af.exclude) if (includedAudioFiles.length === 1) { @@ -407,44 +505,55 @@ class Book { this.chapters = [] var currChapterId = 0 var currStartTime = 0 - includedAudioFiles.forEach((file) => { - // 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 overdriveMediaMarkers = includedAudioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined) || [] + Logger.debug(`[setChapters] overdriveMediaMarkers: ${JSON.stringify(overdriveMediaMarkers)}`) + + // If preferOverdriveMediaMarker is set, try and use that first + if (preferOverdriveMediaMarker) { + Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`) + this.chapters = this.generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) + + } else { + 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 + } } - 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 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 + } + }) + } } } diff --git a/server/objects/settings/ServerSettings.js b/server/objects/settings/ServerSettings.js index 286e15c0..00c56b2a 100644 --- a/server/objects/settings/ServerSettings.js +++ b/server/objects/settings/ServerSettings.js @@ -13,6 +13,7 @@ class ServerSettings { this.scannerPreferOpfMetadata = false this.scannerPreferMatchedMetadata = false this.scannerDisableWatcher = false + this.scannerPreferOverdriveMediaMarker = false // Metadata - choose to store inside users library item folder this.storeCoverWithItem = false @@ -65,6 +66,7 @@ class ServerSettings { this.scannerPreferOpfMetadata = !!settings.scannerPreferOpfMetadata this.scannerPreferMatchedMetadata = !!settings.scannerPreferMatchedMetadata this.scannerDisableWatcher = !!settings.scannerDisableWatcher + this.scannerPreferOverdriveMediaMarker = !!settings.scannerPreferOverdriveMediaMarker this.storeCoverWithItem = !!settings.storeCoverWithItem if (settings.storeCoverWithBook != undefined) { // storeCoverWithBook was old name of setting < v2 @@ -111,6 +113,7 @@ class ServerSettings { scannerPreferOpfMetadata: this.scannerPreferOpfMetadata, scannerPreferMatchedMetadata: this.scannerPreferMatchedMetadata, scannerDisableWatcher: this.scannerDisableWatcher, + scannerPreferOverdriveMediaMarker: this.scannerPreferOverdriveMediaMarker, storeCoverWithItem: this.storeCoverWithItem, storeMetadataWithItem: this.storeMetadataWithItem, rateLimitLoginRequests: this.rateLimitLoginRequests, diff --git a/server/scanner/MediaFileScanner.js b/server/scanner/MediaFileScanner.js index bccbae26..d10e185f 100644 --- a/server/scanner/MediaFileScanner.js +++ b/server/scanner/MediaFileScanner.js @@ -196,6 +196,9 @@ class MediaFileScanner { } async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, libraryScan = null) { + Logger.debug('[scanMediaFiles] inside scan media files!') + Logger.debug(`[scanMediaFiles] libraryScan: ${JSON.stringify(libraryScan)}`) + var hasUpdated = false var mediaScanResult = await this.executeMediaFileScans(libraryItem.mediaType, mediaLibraryFiles, scanData) @@ -208,6 +211,7 @@ class MediaFileScanner { } else if (mediaScanResult.audioFiles.length) { if (libraryScan) { libraryScan.addLog(LogLevel.DEBUG, `Library Item "${scanData.path}" Audio file scan took ${mediaScanResult.elapsed}ms for ${mediaScanResult.audioFiles.length} with average time of ${mediaScanResult.averageScanDuration}ms`) + Logger.debug(`Library Item "${scanData.path}" Audio file scan took ${mediaScanResult.elapsed}ms for ${mediaScanResult.audioFiles.length} with average time of ${mediaScanResult.averageScanDuration}ms`) } var totalAudioFilesToInclude = mediaScanResult.audioFiles.length @@ -217,18 +221,23 @@ class MediaFileScanner { // Book: Adding audio files to book media if (libraryItem.mediaType === 'book') { + Logger.debug('Its a book!') if (newAudioFiles.length) { + Logger.debug('[MediaFileScanner] newAudioFiles.length was true?') // Single Track Audiobooks if (totalAudioFilesToInclude === 1) { + Logger.debug('[MediaFileScanner] totalAudioFilesToInclude === 1') var af = mediaScanResult.audioFiles[0] af.index = 1 libraryItem.media.addAudioFile(af) hasUpdated = true } else { + Logger.debug('[MediaFileScanner] totalAudioFilesToInclude === 1 WAS FALSE') this.runSmartTrackOrder(libraryItem, mediaScanResult.audioFiles) hasUpdated = true } } else { + Logger.debug('[MediaFileScanner] Only updating metadata?') // Only update metadata not index mediaScanResult.audioFiles.forEach((af) => { var existingAF = libraryItem.media.findFileWithInode(af.ino) @@ -247,7 +256,9 @@ class MediaFileScanner { } if (hasUpdated) { - libraryItem.media.rebuildTracks() + Logger.debug('[MediaFileScanner] hasUpdated is true! Going to rebuild tracks now...') + Logger.debug(`[MediaFileScanner] libraryScan: ${JSON.stringify(libraryScan)}`) + libraryItem.media.rebuildTracks(libraryScan.scanOptions.preferOverdriveMediaMarker) } } else { // Podcast Media Type var existingAudioFiles = mediaScanResult.audioFiles.filter(af => libraryItem.media.findFileWithInode(af.ino)) @@ -264,6 +275,7 @@ class MediaFileScanner { // Update audio file metadata for audio files already there existingAudioFiles.forEach((af) => { var peAudioFile = libraryItem.media.findFileWithInode(af.ino) + Logger.debug(`[MediaFileScanner] peAudioFile: ${JSON.stringify(peAudioFile)}`) if (peAudioFile.updateFromScan && peAudioFile.updateFromScan(af)) { hasUpdated = true } diff --git a/server/scanner/ScanOptions.js b/server/scanner/ScanOptions.js index 3d9d4556..968f0723 100644 --- a/server/scanner/ScanOptions.js +++ b/server/scanner/ScanOptions.js @@ -9,6 +9,7 @@ class ScanOptions { this.preferAudioMetadata = false this.preferOpfMetadata = false this.preferMatchedMetadata = false + this.preferOverdriveMediaMarker = false if (options) { this.construct(options) @@ -34,7 +35,8 @@ class ScanOptions { storeCoverWithItem: this.storeCoverWithItem, preferAudioMetadata: this.preferAudioMetadata, preferOpfMetadata: this.preferOpfMetadata, - preferMatchedMetadata: this.preferMatchedMetadata + preferMatchedMetadata: this.preferMatchedMetadata, + preferOverdriveMediaMarker: this.preferOverdriveMediaMarker } } @@ -47,6 +49,7 @@ class ScanOptions { this.preferAudioMetadata = serverSettings.scannerPreferAudioMetadata this.preferOpfMetadata = serverSettings.scannerPreferOpfMetadata this.scannerPreferMatchedMetadata = serverSettings.scannerPreferMatchedMetadata + this.preferOverdriveMediaMarker = serverSettings.scannerPreferOverdriveMediaMarker } } module.exports = ScanOptions \ No newline at end of file diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 677585e1..6832e27a 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -62,6 +62,7 @@ class Scanner { } async scanLibraryItem(libraryMediaType, folder, libraryItem) { + Logger.debug(`[Scanner] SCANNING ITEMS JOE`) // TODO: Support for single media item var libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, libraryItem.path, false, this.db.serverSettings) if (!libraryItemData) { @@ -114,6 +115,7 @@ class Scanner { } async scan(library, options = {}) { + Logger.debug('[scan] inside of scan') if (this.isLibraryScanning(library.id)) { Logger.error(`[Scanner] Already scanning ${library.id}`) return @@ -126,6 +128,7 @@ class Scanner { var scanOptions = new ScanOptions() scanOptions.setData(options, this.db.serverSettings) + Logger.debug(`[Scanner] scanOptions: ${JSON.stringify(scanOptions)}`) var libraryScan = new LibraryScan() libraryScan.setData(library, scanOptions) @@ -165,6 +168,8 @@ class Scanner { async scanLibrary(libraryScan) { var libraryItemDataFound = [] + Logger.debug(`[scanLibrary] libraryScan: ${JSON.stringify(libraryScan)}`) + // Scan each library for (let i = 0; i < libraryScan.folders.length; i++) { var folder = libraryScan.folders[i] @@ -750,6 +755,7 @@ class Scanner { } async matchLibraryItems(library) { + Logger.debug("SCANNING!") if (library.mediaType === 'podcast') { Logger.error(`[Scanner] matchLibraryItems: Match all not supported for podcasts yet`) return From 68afc2c718dab441f39ba7ed9df349a4dbbe2ee4 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sat, 11 Jun 2022 23:56:36 -0700 Subject: [PATCH 08/21] Add support for various scan types This commit adds support for the various scan types, and ensures that we only run Overdrive parsing on files that can actually support it --- server/objects/mediaTypes/Book.js | 42 ++++++++++++++++-------------- server/scanner/MediaFileScanner.js | 6 ++--- server/scanner/Scanner.js | 14 +++++----- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index d8ee7528..83a059f7 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -360,9 +360,9 @@ class Book { this.rebuildTracks() } - rebuildTracks(preferOverdriveMediaMarker = false) { + rebuildTracks(preferOverdriveMediaMarker) { Logger.debug(`[Book] we are rebuilding the tracks!`) - Logger.debug(`[Book] preferOverdriveMediaMarker: ${preferOverdriveMediaMarker}`) + Logger.debug(`[Book] preferOverdriveMediaMarker: ${JSON.stringify(preferOverdriveMediaMarker)}`) this.audioFiles.sort((a, b) => a.index - b.index) this.missingParts = [] this.setChapters(preferOverdriveMediaMarker) @@ -491,29 +491,33 @@ class Book { return newOChapters } + getOverdriveMediaMarkers(audioFiles) { + var markers = audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] + return markers + } + setChapters(preferOverdriveMediaMarker = false) { - Logger.debug('[Book] inside setChapters!') // If 1 audio file without chapters, then no chapters will be set var includedAudioFiles = this.audioFiles.filter(af => !af.exclude) - if (includedAudioFiles.length === 1) { - // 1 audio file with chapters - if (includedAudioFiles[0].chapters) { - this.chapters = includedAudioFiles[0].chapters.map(c => ({ ...c })) - } + + var overdriveMediaMarkers = this.getOverdriveMediaMarkers(includedAudioFiles) + + // If preferOverdriveMediaMarker is set, try and use that first + // fallback to non-overdrive chapters if there are no Overdrive Media Markers available + if (preferOverdriveMediaMarker && (overdriveMediaMarkers.length > 0)) { + Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`) + this.chapters = this.generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) } else { - this.chapters = [] - var currChapterId = 0 - var currStartTime = 0 - var overdriveMediaMarkers = includedAudioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined) || [] - Logger.debug(`[setChapters] overdriveMediaMarkers: ${JSON.stringify(overdriveMediaMarkers)}`) - - // If preferOverdriveMediaMarker is set, try and use that first - if (preferOverdriveMediaMarker) { - Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`) - this.chapters = this.generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) - + 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 diff --git a/server/scanner/MediaFileScanner.js b/server/scanner/MediaFileScanner.js index d10e185f..7b993a0a 100644 --- a/server/scanner/MediaFileScanner.js +++ b/server/scanner/MediaFileScanner.js @@ -195,7 +195,7 @@ class MediaFileScanner { } } - async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, libraryScan = null) { + async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan = null) { Logger.debug('[scanMediaFiles] inside scan media files!') Logger.debug(`[scanMediaFiles] libraryScan: ${JSON.stringify(libraryScan)}`) @@ -257,8 +257,8 @@ class MediaFileScanner { if (hasUpdated) { Logger.debug('[MediaFileScanner] hasUpdated is true! Going to rebuild tracks now...') - Logger.debug(`[MediaFileScanner] libraryScan: ${JSON.stringify(libraryScan)}`) - libraryItem.media.rebuildTracks(libraryScan.scanOptions.preferOverdriveMediaMarker) + Logger.debug(`[MediaFileScanner] preferOverdriveMediaMarker: ${JSON.stringify(preferOverdriveMediaMarker)}`) + libraryItem.media.rebuildTracks(preferOverdriveMediaMarker) } } else { // Podcast Media Type var existingAudioFiles = mediaScanResult.audioFiles.filter(af => libraryItem.media.findFileWithInode(af.ino)) diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 6832e27a..fe8f1d0a 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -81,7 +81,7 @@ class Scanner { // Scan all audio files if (libraryItem.hasAudioFiles) { var libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio') - if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata)) { + if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata, this.db.serverSettings.scannerPreferOverdriveMediaMarker)) { hasUpdated = true } @@ -315,7 +315,7 @@ class Scanner { async scanNewLibraryItemDataChunk(newLibraryItemsData, libraryScan) { var newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => { - return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan) + return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.preferOverdriveMediaMarker, libraryScan) })) newLibraryItems = newLibraryItems.filter(li => li) // Filter out nulls @@ -342,7 +342,7 @@ class Scanner { // forceRescan all existing audio files - will probe and update ID3 tag metadata var existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio') if (libraryScan.scanOptions.forceRescan && existingAudioFiles.length) { - if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan)) { + if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } @@ -350,7 +350,7 @@ class Scanner { var newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio') var removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio') if (newAudioFiles.length || removedAudioFiles.length) { - if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan)) { + if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } @@ -384,7 +384,7 @@ class Scanner { return hasUpdated ? libraryItem : null } - async scanNewLibraryItem(libraryItemData, libraryMediaType, preferAudioMetadata, preferOpfMetadata, findCovers, libraryScan = null) { + async scanNewLibraryItem(libraryItemData, libraryMediaType, preferAudioMetadata, preferOpfMetadata, findCovers, preferOverdriveMediaMarker, libraryScan = null) { if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Scanning new library item "${libraryItemData.path}"`) else Logger.debug(`[Scanner] Scanning new item "${libraryItemData.path}"`) @@ -393,7 +393,7 @@ class Scanner { var mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video') if (mediaFiles.length) { - await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, libraryScan) + await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan) } await libraryItem.syncFiles(preferOpfMetadata) @@ -613,7 +613,7 @@ class Scanner { var libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, fullPath, isSingleMediaItem, this.db.serverSettings) if (!libraryItemData) return null var serverSettings = this.db.serverSettings - return this.scanNewLibraryItem(libraryItemData, libraryMediaType, serverSettings.scannerPreferAudioMetadata, serverSettings.scannerPreferOpfMetadata, serverSettings.scannerFindCovers) + return this.scanNewLibraryItem(libraryItemData, libraryMediaType, serverSettings.scannerPreferAudioMetadata, serverSettings.scannerPreferOpfMetadata, serverSettings.scannerFindCovers, serverSettings.scannerPreferOverdriveMediaMarker) } async searchForCover(libraryItem, libraryScan = null) { From 3d85d0bce67ed2ce868f598172bb05063639a5d4 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 00:21:37 -0700 Subject: [PATCH 09/21] add settings page setting --- client/pages/config/index.vue | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/client/pages/config/index.vue b/client/pages/config/index.vue index a037ac71..3dda0a60 100644 --- a/client/pages/config/index.vue +++ b/client/pages/config/index.vue @@ -103,6 +103,16 @@ +
+ + +

+ Scanner prefer Overdrive Media Markers for chapters + info_outlined +

+
+
+
@@ -245,7 +255,8 @@ export default { storeCoverWithItem: 'By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named "cover" will be kept', storeMetadataWithItem: 'By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension', coverAspectRatio: 'Prefer to use square covers over standard 1.6:1 book covers', - enableEReader: 'E-reader is still a work in progress, but use this setting to open it up to all your users (or use the "Experimental Features" toggle below just for you)' + enableEReader: 'E-reader is still a work in progress, but use this setting to open it up to all your users (or use the "Experimental Features" toggle below just for you)', + scannerPreferOverdriveMediaMarker: 'MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically' }, showConfirmPurgeCache: false } From 5a071babe9b4bcde2e69a1b8a9610b73bdeb9c49 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 00:22:04 -0700 Subject: [PATCH 10/21] added library/ to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 769b0639..53a60bef 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ test/ /client/.nuxt/ /client/dist/ /dist/ +library/ sw.* -.DS_STORE \ No newline at end of file +.DS_STORE From 5643c846eeba32a0f6467e4a793517d1f801c32f Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 00:47:54 -0700 Subject: [PATCH 11/21] Fix bug for certain scan types Needed to look in to scanOptions to access the properties I wanted. It's..... unclear to me if this needs to be done for those other ones as well. I think so? --- server/objects/mediaTypes/Book.js | 2 +- server/scanner/Scanner.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index 83a059f7..8048911d 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -357,6 +357,7 @@ class Book { return audioFile }) + Logger.debug(`[Book] WE ARE INSIDE UPDATE AUDIO TRACKS ========================`) this.rebuildTracks() } @@ -496,7 +497,6 @@ class Book { return markers } - setChapters(preferOverdriveMediaMarker = false) { // If 1 audio file without chapters, then no chapters will be set var includedAudioFiles = this.audioFiles.filter(af => !af.exclude) diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index fe8f1d0a..832f2889 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -81,6 +81,7 @@ class Scanner { // Scan all audio files if (libraryItem.hasAudioFiles) { var libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio') + Logger.debug(`[Scanner] //scan all audio files -- This is this.db.serverSettings.scannerPreferOverdriveMediaMarker: ${this.db.serverSettings.scannerPreferOverdriveMediaMarker}`) if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata, this.db.serverSettings.scannerPreferOverdriveMediaMarker)) { hasUpdated = true } @@ -342,7 +343,10 @@ class Scanner { // forceRescan all existing audio files - will probe and update ID3 tag metadata var existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio') if (libraryScan.scanOptions.forceRescan && existingAudioFiles.length) { - if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { + Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.scanOptions.preferOverdriveMediaMarker}`) + Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan: ${JSON.stringify(libraryScan)}`) + + if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } @@ -350,7 +354,8 @@ class Scanner { var newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio') var removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio') if (newAudioFiles.length || removedAudioFiles.length) { - if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { + Logger.debug(`[Scanner] // Scan new audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.scanOptions.preferOverdriveMediaMarker}`) + if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } @@ -393,6 +398,7 @@ class Scanner { var mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video') if (mediaFiles.length) { + Logger.debug(`[Scanner] // :399 -- this is preferOverdriveMediaMarker: ${preferOverdriveMediaMarker}`) await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan) } From 9877b139f684724f455f1efb9f2826965ae2ab52 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 00:53:56 -0700 Subject: [PATCH 12/21] add new parser for overdrive media markers --- server/objects/mediaTypes/Book.js | 104 +----------------- .../parsers/parseOverdriveMediaMarkers.js | 101 +++++++++++++++++ 2 files changed, 104 insertions(+), 101 deletions(-) create mode 100644 server/utils/parsers/parseOverdriveMediaMarkers.js diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index 8048911d..c9d4d429 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -3,6 +3,7 @@ const Logger = require('../../Logger') const BookMetadata = require('../metadata/BookMetadata') const { areEquivalent, copyValue } = require('../../utils/index') const { parseOpfMetadataXML } = require('../../utils/parsers/parseOpfMetadata') +const { getOverdriveMediaMarkersFromFiles, parseOverdriveMediaMarkers } = require('../../utils/parsers/parseOverdriveMediaMarkers') const abmetadataGenerator = require('../../utils/abmetadataGenerator') const { readTextFile } = require('../../utils/fileUtils') const AudioFile = require('../files/AudioFile') @@ -398,116 +399,17 @@ class Book { return wasUpdated } - generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) { - var parseString = require('xml2js').parseString; // function to convert xml to JSON - - 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 - // end result looks like: - // [ - // { - // "Name": "Chapter 1: The Worst Birthday", - // "Time": "0:00.000" - // }, - // { - // "Name": "Chapter 2: Dobby's Warning", - // "Time": "15:51.000" - // }, - // { redacted } - // ] - parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers - - var index = 0 - - var time = 0.0 - - - // actually generate the chapter object - // logic ported over from benonymity's OverdriveChapterizer: - // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py - var length = 0.0 - var newOChapters = [] - const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ - includedAudioFiles.forEach((track, track_index) => { - parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { - Logger.debug(`[Book] Attempting regex check for ${chapter.Name}!`) - if (weirdChapterFilterRegex.test(chapter.Name)) { - Logger.debug(`[Book] That shit weird yo`) - return - } - time = chapter.Time.split(":") - time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) - newOChapters.push( - { - id: index++, - start: time, - end: length, - title: chapter.Name - } - ) - }) - length += track.duration - }) - - Logger.debug(`[Book] newOChapters: ${JSON.stringify(newOChapters)}`) - return newOChapters - } - - getOverdriveMediaMarkers(audioFiles) { - var markers = audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] - return markers - } - setChapters(preferOverdriveMediaMarker = false) { // If 1 audio file without chapters, then no chapters will be set var includedAudioFiles = this.audioFiles.filter(af => !af.exclude) - var overdriveMediaMarkers = this.getOverdriveMediaMarkers(includedAudioFiles) + var overdriveMediaMarkers = getOverdriveMediaMarkersFromFiles(includedAudioFiles) // If preferOverdriveMediaMarker is set, try and use that first // fallback to non-overdrive chapters if there are no Overdrive Media Markers available if (preferOverdriveMediaMarker && (overdriveMediaMarkers.length > 0)) { Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`) - this.chapters = this.generateChaptersFromOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) + this.chapters = parseOverdriveMediaMarkers(overdriveMediaMarkers, includedAudioFiles) } else { if (includedAudioFiles.length === 1) { // 1 audio file with chapters diff --git a/server/utils/parsers/parseOverdriveMediaMarkers.js b/server/utils/parsers/parseOverdriveMediaMarkers.js new file mode 100644 index 00000000..859711ca --- /dev/null +++ b/server/utils/parsers/parseOverdriveMediaMarkers.js @@ -0,0 +1,101 @@ +const Logger = require('../../Logger') + +// given an array of audioFiles, return an array of unparsed MediaMarkers +module.exports.getOverdriveMediaMarkersFromFiles = (audioFiles) => { + var markers = audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] + return markers +} + +module.exports.parseOverdriveMediaMarkers = (overdriveMediaMarkers, includedAudioFiles) => { + var parseString = require('xml2js').parseString; // function to convert xml to JSON + + 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 + // end result looks like: + // [ + // { + // "Name": "Chapter 1: The Worst Birthday", + // "Time": "0:00.000" + // }, + // { + // "Name": "Chapter 2: Dobby's Warning", + // "Time": "15:51.000" + // }, + // { redacted } + // ] + parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers + + var index = 0 + + var time = 0.0 + + + // actually generate the chapter object + // logic ported over from benonymity's OverdriveChapterizer: + // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py + var length = 0.0 + var newOChapters = [] + const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ + includedAudioFiles.forEach((track, track_index) => { + parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { + Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}!`) + if (weirdChapterFilterRegex.test(chapter.Name)) { + Logger.debug(`[parseOverdriveMediaMarkers] That shit weird yo`) + return + } + time = chapter.Time.split(":") + time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) + newOChapters.push( + { + id: index++, + start: time, + end: length, + title: chapter.Name + } + ) + }) + length += track.duration + }) + + Logger.debug(`[parseOverdriveMediaMarkers] newOChapters: ${JSON.stringify(newOChapters)}`) + return newOChapters +} \ No newline at end of file From f31700f668e3da5a55a638132231fedb4819d4a7 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 00:54:34 -0700 Subject: [PATCH 13/21] update comments --- server/utils/parsers/parseOverdriveMediaMarkers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/utils/parsers/parseOverdriveMediaMarkers.js b/server/utils/parsers/parseOverdriveMediaMarkers.js index 859711ca..58d5003c 100644 --- a/server/utils/parsers/parseOverdriveMediaMarkers.js +++ b/server/utils/parsers/parseOverdriveMediaMarkers.js @@ -53,11 +53,11 @@ module.exports.parseOverdriveMediaMarkers = (overdriveMediaMarkers, includedAudi // end result looks like: // [ // { - // "Name": "Chapter 1: The Worst Birthday", + // "Name": "Chapter 1", // "Time": "0:00.000" // }, // { - // "Name": "Chapter 2: Dobby's Warning", + // "Name": "Chapter 2", // "Time": "15:51.000" // }, // { redacted } From 8754f0c25ff8d70f00e37d1d51b53bf97fa34c33 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 01:38:09 -0700 Subject: [PATCH 14/21] Cleaning up server code Doing some literal cleaning --- server/objects/mediaTypes/Book.js | 109 ++++++------- .../parsers/parseOverdriveMediaMarkers.js | 154 ++++++++++-------- 2 files changed, 136 insertions(+), 127 deletions(-) diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index c9d4d429..ed791e31 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -3,7 +3,7 @@ const Logger = require('../../Logger') const BookMetadata = require('../metadata/BookMetadata') const { areEquivalent, copyValue } = require('../../utils/index') 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 { readTextFile } = require('../../utils/fileUtils') const AudioFile = require('../files/AudioFile') @@ -403,63 +403,60 @@ class Book { // If 1 audio file without chapters, then no chapters will be set 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 - // fallback to non-overdrive chapters if there are no Overdrive Media Markers available - if (preferOverdriveMediaMarker && (overdriveMediaMarkers.length > 0)) { - Logger.debug(`[Book] preferring overdrive media markers! Lets generate em.`) - 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 - } - }) + 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 + } + }) } } diff --git a/server/utils/parsers/parseOverdriveMediaMarkers.js b/server/utils/parsers/parseOverdriveMediaMarkers.js index 58d5003c..da323924 100644 --- a/server/utils/parsers/parseOverdriveMediaMarkers.js +++ b/server/utils/parsers/parseOverdriveMediaMarkers.js @@ -1,53 +1,16 @@ const Logger = require('../../Logger') -// given an array of audioFiles, return an array of unparsed MediaMarkers -module.exports.getOverdriveMediaMarkersFromFiles = (audioFiles) => { - var markers = audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] +// given a list of audio files, extract all of the Overdrive Media Markers metaTags, and return an array of them as XML +function overdriveMediaMarkers(includedAudioFiles) { + var markers = includedAudioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] 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 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) - }) + var parsedOverdriveMediaMarkers = [] // go from an array of arrays of objects to an array of objects // end result looks like: @@ -62,40 +25,89 @@ module.exports.parseOverdriveMediaMarkers = (overdriveMediaMarkers, includedAudi // }, // { 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 - - var time = 0.0 - + 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) + }) + + return parsedOverdriveMediaMarkers +} + +// The function that actually generates the Chapters object that we update ABS with +function generateParsedChapters(includedAudioFiles, cleanedOverdriveMediaMarkers) { // actually generate the chapter object // logic ported over from benonymity's OverdriveChapterizer: // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py var length = 0.0 - var newOChapters = [] + var index = 0 + var time = 0.0 + var newChapters = [] const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ includedAudioFiles.forEach((track, track_index) => { - parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { - Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}!`) - if (weirdChapterFilterRegex.test(chapter.Name)) { - Logger.debug(`[parseOverdriveMediaMarkers] That shit weird yo`) - return - } - time = chapter.Time.split(":") - time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) - newOChapters.push( - { - id: index++, - start: time, - end: length, - title: chapter.Name - } - ) - }) - length += track.duration + cleanedOverdriveMediaMarkers[track_index].forEach((chapter) => { + Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}...`) + if (weirdChapterFilterRegex.test(chapter.Name)) { + Logger.debug(`[parseOverdriveMediaMarkers] Regex matched. Skipping ${chapter.Name}!`) + return + } + time = chapter.Time.split(":") + time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) + newChapters.push( + { + id: index++, + start: time, + end: length, + title: chapter.Name + } + ) + }) + length += track.duration }) - Logger.debug(`[parseOverdriveMediaMarkers] newOChapters: ${JSON.stringify(newOChapters)}`) - return newOChapters -} \ No newline at end of file + return newChapters +} + +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 +} From 6064e8af876acff05081a3ca6622d14fa90211c4 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 01:46:50 -0700 Subject: [PATCH 15/21] fix using OMMs with regular scan option --- server/objects/mediaTypes/Book.js | 3 +-- server/scanner/Scanner.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index ed791e31..3b6676a8 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -358,12 +358,11 @@ class Book { return audioFile }) - Logger.debug(`[Book] WE ARE INSIDE UPDATE AUDIO TRACKS ========================`) this.rebuildTracks() } rebuildTracks(preferOverdriveMediaMarker) { - Logger.debug(`[Book] we are rebuilding the tracks!`) + Logger.debug(`[Book] Tracks being rebuilt...!`) Logger.debug(`[Book] preferOverdriveMediaMarker: ${JSON.stringify(preferOverdriveMediaMarker)}`) this.audioFiles.sort((a, b) => a.index - b.index) this.missingParts = [] diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 832f2889..f72dd7f8 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -316,7 +316,7 @@ class Scanner { async scanNewLibraryItemDataChunk(newLibraryItemsData, libraryScan) { var newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => { - return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.preferOverdriveMediaMarker, libraryScan) + return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan) })) newLibraryItems = newLibraryItems.filter(li => li) // Filter out nulls From cbd7294b0ba04c3fc65e6fc075d20d716edd1dc3 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 01:54:58 -0700 Subject: [PATCH 16/21] add getter to libraryscan.js for overdrivemediamarker --- server/scanner/LibraryScan.js | 1 + server/scanner/Scanner.js | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/server/scanner/LibraryScan.js b/server/scanner/LibraryScan.js index e089e844..d6d50b27 100644 --- a/server/scanner/LibraryScan.js +++ b/server/scanner/LibraryScan.js @@ -34,6 +34,7 @@ class LibraryScan { get forceRescan() { return !!this._scanOptions.forceRescan } get preferAudioMetadata() { return !!this._scanOptions.preferAudioMetadata } get preferOpfMetadata() { return !!this._scanOptions.preferOpfMetadata } + get preferOverdriveMediaMarker() { return !!this._scanOptions.preferOverdriveMediaMarker } get findCovers() { return !!this._scanOptions.findCovers } get timestamp() { return (new Date()).toISOString() diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index f72dd7f8..7af6c40f 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -315,8 +315,9 @@ class Scanner { } async scanNewLibraryItemDataChunk(newLibraryItemsData, libraryScan) { + Logger.debug(`LIBRARYSCAN: ${JSON.stringify(libraryScan)}`) var newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => { - return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan) + return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.preferOverdriveMediaMarker, libraryScan) })) newLibraryItems = newLibraryItems.filter(li => li) // Filter out nulls @@ -343,10 +344,10 @@ class Scanner { // forceRescan all existing audio files - will probe and update ID3 tag metadata var existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio') if (libraryScan.scanOptions.forceRescan && existingAudioFiles.length) { - Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.scanOptions.preferOverdriveMediaMarker}`) + Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.preferOverdriveMediaMarker}`) Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan: ${JSON.stringify(libraryScan)}`) - if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan)) { + if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } @@ -354,8 +355,8 @@ class Scanner { var newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio') var removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio') if (newAudioFiles.length || removedAudioFiles.length) { - Logger.debug(`[Scanner] // Scan new audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.scanOptions.preferOverdriveMediaMarker}`) - if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.scanOptions.preferOverdriveMediaMarker, libraryScan)) { + Logger.debug(`[Scanner] // Scan new audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.preferOverdriveMediaMarker}`) + if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } } From 8210eba43953e7153f9aa0972295147d7c0a384a Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 01:57:00 -0700 Subject: [PATCH 17/21] clean up loggers --- server/scanner/MediaFileScanner.js | 10 ---------- server/scanner/Scanner.js | 2 -- 2 files changed, 12 deletions(-) diff --git a/server/scanner/MediaFileScanner.js b/server/scanner/MediaFileScanner.js index 7b993a0a..d29929b3 100644 --- a/server/scanner/MediaFileScanner.js +++ b/server/scanner/MediaFileScanner.js @@ -196,9 +196,6 @@ class MediaFileScanner { } async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan = null) { - Logger.debug('[scanMediaFiles] inside scan media files!') - Logger.debug(`[scanMediaFiles] libraryScan: ${JSON.stringify(libraryScan)}`) - var hasUpdated = false var mediaScanResult = await this.executeMediaFileScans(libraryItem.mediaType, mediaLibraryFiles, scanData) @@ -221,23 +218,18 @@ class MediaFileScanner { // Book: Adding audio files to book media if (libraryItem.mediaType === 'book') { - Logger.debug('Its a book!') if (newAudioFiles.length) { - Logger.debug('[MediaFileScanner] newAudioFiles.length was true?') // Single Track Audiobooks if (totalAudioFilesToInclude === 1) { - Logger.debug('[MediaFileScanner] totalAudioFilesToInclude === 1') var af = mediaScanResult.audioFiles[0] af.index = 1 libraryItem.media.addAudioFile(af) hasUpdated = true } else { - Logger.debug('[MediaFileScanner] totalAudioFilesToInclude === 1 WAS FALSE') this.runSmartTrackOrder(libraryItem, mediaScanResult.audioFiles) hasUpdated = true } } else { - Logger.debug('[MediaFileScanner] Only updating metadata?') // Only update metadata not index mediaScanResult.audioFiles.forEach((af) => { var existingAF = libraryItem.media.findFileWithInode(af.ino) @@ -257,7 +249,6 @@ class MediaFileScanner { if (hasUpdated) { Logger.debug('[MediaFileScanner] hasUpdated is true! Going to rebuild tracks now...') - Logger.debug(`[MediaFileScanner] preferOverdriveMediaMarker: ${JSON.stringify(preferOverdriveMediaMarker)}`) libraryItem.media.rebuildTracks(preferOverdriveMediaMarker) } } else { // Podcast Media Type @@ -275,7 +266,6 @@ class MediaFileScanner { // Update audio file metadata for audio files already there existingAudioFiles.forEach((af) => { var peAudioFile = libraryItem.media.findFileWithInode(af.ino) - Logger.debug(`[MediaFileScanner] peAudioFile: ${JSON.stringify(peAudioFile)}`) if (peAudioFile.updateFromScan && peAudioFile.updateFromScan(af)) { hasUpdated = true } diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 7af6c40f..bde45ec9 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -62,7 +62,6 @@ class Scanner { } async scanLibraryItem(libraryMediaType, folder, libraryItem) { - Logger.debug(`[Scanner] SCANNING ITEMS JOE`) // TODO: Support for single media item var libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, libraryItem.path, false, this.db.serverSettings) if (!libraryItemData) { @@ -81,7 +80,6 @@ class Scanner { // Scan all audio files if (libraryItem.hasAudioFiles) { var libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio') - Logger.debug(`[Scanner] //scan all audio files -- This is this.db.serverSettings.scannerPreferOverdriveMediaMarker: ${this.db.serverSettings.scannerPreferOverdriveMediaMarker}`) if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata, this.db.serverSettings.scannerPreferOverdriveMediaMarker)) { hasUpdated = true } From d43d351721ff9849283a782907bfb2bad0be1bb4 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 02:03:26 -0700 Subject: [PATCH 18/21] remove loggers --- server/objects/mediaTypes/Book.js | 2 -- server/scanner/MediaFileScanner.js | 1 - server/scanner/Scanner.js | 10 ---------- 3 files changed, 13 deletions(-) diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index 3b6676a8..e84980d0 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -363,7 +363,6 @@ class Book { rebuildTracks(preferOverdriveMediaMarker) { Logger.debug(`[Book] Tracks being rebuilt...!`) - Logger.debug(`[Book] preferOverdriveMediaMarker: ${JSON.stringify(preferOverdriveMediaMarker)}`) this.audioFiles.sort((a, b) => a.index - b.index) this.missingParts = [] this.setChapters(preferOverdriveMediaMarker) @@ -418,7 +417,6 @@ class Book { 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) => { diff --git a/server/scanner/MediaFileScanner.js b/server/scanner/MediaFileScanner.js index d29929b3..3d43d85e 100644 --- a/server/scanner/MediaFileScanner.js +++ b/server/scanner/MediaFileScanner.js @@ -248,7 +248,6 @@ class MediaFileScanner { } if (hasUpdated) { - Logger.debug('[MediaFileScanner] hasUpdated is true! Going to rebuild tracks now...') libraryItem.media.rebuildTracks(preferOverdriveMediaMarker) } } else { // Podcast Media Type diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index bde45ec9..976c5a45 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -114,7 +114,6 @@ class Scanner { } async scan(library, options = {}) { - Logger.debug('[scan] inside of scan') if (this.isLibraryScanning(library.id)) { Logger.error(`[Scanner] Already scanning ${library.id}`) return @@ -127,7 +126,6 @@ class Scanner { var scanOptions = new ScanOptions() scanOptions.setData(options, this.db.serverSettings) - Logger.debug(`[Scanner] scanOptions: ${JSON.stringify(scanOptions)}`) var libraryScan = new LibraryScan() libraryScan.setData(library, scanOptions) @@ -167,8 +165,6 @@ class Scanner { async scanLibrary(libraryScan) { var libraryItemDataFound = [] - Logger.debug(`[scanLibrary] libraryScan: ${JSON.stringify(libraryScan)}`) - // Scan each library for (let i = 0; i < libraryScan.folders.length; i++) { var folder = libraryScan.folders[i] @@ -342,9 +338,6 @@ class Scanner { // forceRescan all existing audio files - will probe and update ID3 tag metadata var existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio') if (libraryScan.scanOptions.forceRescan && existingAudioFiles.length) { - Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.preferOverdriveMediaMarker}`) - Logger.debug(`[Scanner] // forceRescan all existing audio files -- this is libraryScan: ${JSON.stringify(libraryScan)}`) - if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } @@ -353,7 +346,6 @@ class Scanner { var newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio') var removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio') if (newAudioFiles.length || removedAudioFiles.length) { - Logger.debug(`[Scanner] // Scan new audio files -- this is libraryScan.preferOverdriveMediaMarker: ${libraryScan.preferOverdriveMediaMarker}`) if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) { hasUpdated = true } @@ -397,7 +389,6 @@ class Scanner { var mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video') if (mediaFiles.length) { - Logger.debug(`[Scanner] // :399 -- this is preferOverdriveMediaMarker: ${preferOverdriveMediaMarker}`) await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan) } @@ -760,7 +751,6 @@ class Scanner { } async matchLibraryItems(library) { - Logger.debug("SCANNING!") if (library.mediaType === 'podcast') { Logger.error(`[Scanner] matchLibraryItems: Match all not supported for podcasts yet`) return From 3279901ab08d6f947f27f7bb1ac687561cc40f1f Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 12:24:29 -0700 Subject: [PATCH 19/21] remove clientside changes --- client/pages/audiobook/_id/chapters.vue | 120 +----------------------- 1 file changed, 2 insertions(+), 118 deletions(-) diff --git a/client/pages/audiobook/_id/chapters.vue b/client/pages/audiobook/_id/chapters.vue index 519d0f14..d5351dd5 100644 --- a/client/pages/audiobook/_id/chapters.vue +++ b/client/pages/audiobook/_id/chapters.vue @@ -22,16 +22,6 @@
-
-
-

Overdrive Media Markers Found! Would you like to generate chapter data from them?

-
- Yes - -
-
-
-
Start
@@ -95,7 +85,6 @@ check
-
@@ -179,7 +168,6 @@ export default { asinInput: null, findingChapters: false, showFindChaptersModal: false, - showImportOverdriveMediaMarkersModal: false, chapterData: null } }, @@ -202,19 +190,13 @@ export default { mediaDuration() { return this.media.duration }, - overdriveMediaMarkersExist() { - return (this.overdriveMediaMarkers?.length > 0 ? true : false ) || false - }, - overdriveMediaMarkers() { - return this.audioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined) || [] - }, chapters() { return this.media.chapters || [] }, tracks() { return this.media.tracks || [] }, - audioFiles() { + audioFiles() { return this.media.audioFiles || [] }, audioTracks() { @@ -225,13 +207,6 @@ export default { } }, methods: { - checkForOverdriveMediaMarkers() { - if (this.overdriveMediaMarkersExist) { - this.$toast.success('Your book has overdrive media markers!') - } else { - this.$toast.error('Your book DOES NOT have overdrive media markers!') - } - }, editItem() { this.$store.commit('showEditModal', this.libraryItem) }, @@ -417,7 +392,7 @@ export default { this.$toast.error(data.error) this.showFindChaptersModal = false } else { - console.log('Chapter data', JSON.stringify(data)) + console.log('Chapter data', data) this.chapterData = data } }) @@ -427,100 +402,9 @@ export default { this.$toast.error('Failed to find chapters') this.showFindChaptersModal = false }) - }, - // overdrive - generateChaptersFromOverdriveMediaMarkers() { - var parseString = require('xml2js').parseString; // function to convert xml to JSON - var overdriveMediaMarkers = this.overdriveMediaMarkers // an array of XML. 1 Part.mp3 to 1 array index. Each index holds 1 XML that holds multiple chapters - - 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 - // end result looks like: - // [ - // { - // "Name": "Chapter 1: The Worst Birthday", - // "Time": "0:00.000" - // }, - // { - // "Name": "Chapter 2: Dobby's Warning", - // "Time": "15:51.000" - // }, - // { redacted } - // ] - parsedOverdriveMediaMarkers = parsedOverdriveMediaMarkers - - var index = 0 - - var time = 0.0 - - - // actually generate the chapter object - // logic ported over from benonymity's OverdriveChapterizer: - // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py - var length = 0.0 - var newOChapters = [] - this.audioTracks.forEach((track, track_index) => { - parsedOverdriveMediaMarkers[track_index].forEach((chapter) => { - time = chapter.Time.split(":") - time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) - newOChapters.push( - { - id: index++, - start: time, - end: length, - title: chapter.Name - } - ) - }) - length += track.duration - }) - - this.newChapters = newOChapters } }, - mounted() { - this.checkForOverdriveMediaMarkers() - var dismissed = false this.asinInput = this.mediaMetadata.asin || null this.newChapters = this.chapters.map((c) => ({ ...c })) if (!this.newChapters.length) { From d03d3735e52b7aeac324c1ea5bd948c11407550e Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 20:28:09 -0700 Subject: [PATCH 20/21] Add chapter end time support --- .../parsers/parseOverdriveMediaMarkers.js | 165 +++++++++++------- 1 file changed, 100 insertions(+), 65 deletions(-) diff --git a/server/utils/parsers/parseOverdriveMediaMarkers.js b/server/utils/parsers/parseOverdriveMediaMarkers.js index da323924..a65e15c3 100644 --- a/server/utils/parsers/parseOverdriveMediaMarkers.js +++ b/server/utils/parsers/parseOverdriveMediaMarkers.js @@ -1,113 +1,148 @@ const Logger = require('../../Logger') // given a list of audio files, extract all of the Overdrive Media Markers metaTags, and return an array of them as XML -function overdriveMediaMarkers(includedAudioFiles) { +function extractOverdriveMediaMarkers(includedAudioFiles) { + Logger.debug('[parseOverdriveMediaMarkers] Extracting overdrive media markers') var markers = includedAudioFiles.map((af) => af.metaTags.tagOverdriveMediaMarker).filter(notUndefined => notUndefined !== undefined).filter(elem => { return elem !== null }) || [] + return markers } // given the array of Overdrive Media Markers from generateOverdriveMediaMarkers() // parse and clean them in to something a bit more usable function cleanOverdriveMediaMarkers(overdriveMediaMarkers) { + Logger.debug('[parseOverdriveMediaMarkers] Cleaning up overdrive media markers') + /* + returns an array of arrays of objects. Each inner array corresponds to an audio track, with it's objects being a chapter: + [ + [ + { + "Name": "Chapter 1", + "Time": "0:00.000" + }, + { + "Name": "Chapter 2", + "Time": "15:51.000" + }, + { etc } + ] + ] + */ + var parseString = require('xml2js').parseString; // function to convert xml to JSON var parsedOverdriveMediaMarkers = [] - // go from an array of arrays of objects to an array of objects - // end result looks like: - // [ - // { - // "Name": "Chapter 1", - // "Time": "0:00.000" - // }, - // { - // "Name": "Chapter 2", - // "Time": "15:51.000" - // }, - // { redacted } - // ] 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" - // ] - // } - // ] + /* + 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, and needs further cleaning below: + [ + { + "Name": [ + "Chapter 1: " + ], + "Time": [ + "0:00.000" + ] + }, + { + ANOTHER CHAPTER + }, + ] + */ - 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() - }) - }) + // The values for Name and Time in results.Markers.Marker are returned as Arrays from parseString and should be strings + parsed_result = objectValuesArrayToString(result.Markers.Marker) }) parsedOverdriveMediaMarkers.push(parsed_result) }) - return parsedOverdriveMediaMarkers + return removeExtraChapters(parsedOverdriveMediaMarkers) +} + +// given an array of objects, convert any values that are arrays to strings +function objectValuesArrayToString(arrayOfObjects) { + Logger.debug('[parseOverdriveMediaMarkers] Converting Marker object values from arrays to strings') + arrayOfObjects.forEach((item) => { + Object.keys(item).forEach(key => { + item[key] = item[key].toString() + }) + }) + + return arrayOfObjects +} + +// Overdrive sometimes has weird chapters and subchapters defined +// These aren't necessary, so lets remove them +function removeExtraChapters(parsedOverdriveMediaMarkers) { + Logger.debug('[parseOverdriveMediaMarkers] Removing any unnecessary chapters') + const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ + var cleaned = [] + parsedOverdriveMediaMarkers.forEach(function (item) { + cleaned.push(item.filter(chapter => !weirdChapterFilterRegex.test(chapter.Name))) + }) + + return cleaned +} + +// Given a set of chapters from generateParsedChapters, add the end time to each one +function addChapterEndTimes(chapters, totalAudioDuration) { + Logger.debug('[parseOverdriveMediaMarkers] Adding chapter end times') + chapters.forEach((chapter, chapter_index) => { + if (chapter_index < chapters.length - 1) { + chapter.end = chapters[chapter_index + 1].start + } else { + chapter.end = totalAudioDuration + } + }) + + return chapters } // The function that actually generates the Chapters object that we update ABS with function generateParsedChapters(includedAudioFiles, cleanedOverdriveMediaMarkers) { - // actually generate the chapter object + Logger.debug('[parseOverdriveMediaMarkers] Generating new chapters for ABS') // logic ported over from benonymity's OverdriveChapterizer: // https://github.com/benonymity/OverdriveChapterizer/blob/main/chapters.py + var parsedChapters = [] var length = 0.0 var index = 0 var time = 0.0 - var newChapters = [] - const weirdChapterFilterRegex = /([(]\d|[cC]ontinued)/ + + // cleanedOverdriveMediaMarkers is an array of array of objects, where the inner array matches to the included audio files tracks + // this allows us to leverage the individual track durations when calculating the start times of chapters in tracks after the first (using length) includedAudioFiles.forEach((track, track_index) => { cleanedOverdriveMediaMarkers[track_index].forEach((chapter) => { - Logger.debug(`[parseOverdriveMediaMarkers] Attempting regex check for ${chapter.Name}...`) - if (weirdChapterFilterRegex.test(chapter.Name)) { - Logger.debug(`[parseOverdriveMediaMarkers] Regex matched. Skipping ${chapter.Name}!`) - return - } time = chapter.Time.split(":") time = length + parseFloat(time[0]) * 60 + parseFloat(time[1]) - newChapters.push( - { - id: index++, - start: time, - end: length, - title: chapter.Name - } - ) + var newChapterData = { + id: index++, + start: time, + title: chapter.Name + } + parsedChapters.push(newChapterData) }) length += track.duration }) - return newChapters + parsedChapters = addChapterEndTimes(parsedChapters, length) // we need all the start times sorted out before we can add the end times + + return parsedChapters } module.exports.overdriveMediaMarkersExist = (includedAudioFiles) => { - return overdriveMediaMarkers(includedAudioFiles).length > 1 + return extractOverdriveMediaMarkers(includedAudioFiles).length > 1 } module.exports.parseOverdriveMediaMarkersAsChapters = (includedAudioFiles) => { Logger.info('[parseOverdriveMediaMarkers] Parsing of Overdrive Media Markers started') - var cleanedOverdriveMediaMarkers = cleanOverdriveMediaMarkers(overdriveMediaMarkers(includedAudioFiles)) + + var overdriveMediaMarkers = extractOverdriveMediaMarkers(includedAudioFiles) + var cleanedOverdriveMediaMarkers = cleanOverdriveMediaMarkers(overdriveMediaMarkers) var parsedChapters = generateParsedChapters(includedAudioFiles, cleanedOverdriveMediaMarkers) - + return parsedChapters -} +} \ No newline at end of file From 863f81e55a9a982a5c4e66526357c9972d5c5af0 Mon Sep 17 00:00:00 2001 From: jmt-gh Date: Sun, 12 Jun 2022 20:43:20 -0700 Subject: [PATCH 21/21] remove logger --- server/scanner/Scanner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 976c5a45..79d11258 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -309,7 +309,6 @@ class Scanner { } async scanNewLibraryItemDataChunk(newLibraryItemsData, libraryScan) { - Logger.debug(`LIBRARYSCAN: ${JSON.stringify(libraryScan)}`) var newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => { return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.preferOverdriveMediaMarker, libraryScan) }))