mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-19 00:18:56 +01:00
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
This commit is contained in:
parent
fc614b9833
commit
27e6b9ce0d
@ -22,6 +22,16 @@
|
|||||||
<div class="w-40" />
|
<div class="w-40" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full max-w-3xl py-4" v-if="overdriveMediaMarkersExist">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<p class="text-sm mb-4">Overdrive Media Markers Found! Would you like to generate chapter data from them?</p>
|
||||||
|
<div class="flex-grow" />
|
||||||
|
<ui-btn color="primary" small class="mx-2" @click="this.generateChaptersFromOverdriveMediaMarkers">Yes</ui-btn>
|
||||||
|
<!-- <ui-btn color="error" small @click="saveChapters">No</ui-btn> -->
|
||||||
|
<div class="w-40" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
||||||
<div class="w-12"></div>
|
<div class="w-12"></div>
|
||||||
<div class="w-32 px-2">Start</div>
|
<div class="w-32 px-2">Start</div>
|
||||||
@ -85,6 +95,7 @@
|
|||||||
<span v-if="(track.chapters || []).length" class="material-icons text-success text-sm">check</span>
|
<span v-if="(track.chapters || []).length" class="material-icons text-success text-sm">check</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -131,6 +142,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</modals-modal>
|
</modals-modal>
|
||||||
|
|
||||||
|
<modals-modal v-model="showImportOverdriveMediaMarkersModal" name="edit-book2" :width="500" :processing="findingChapters">
|
||||||
|
<template #outer>
|
||||||
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden pointer-events-none">
|
||||||
|
<p class="font-book text-3xl text-white truncate pointer-events-none">Find Chapters</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="w-full h-full max-h-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative">
|
||||||
|
<div v-if="!chapterData" class="flex p-20">
|
||||||
|
<ui-text-input-with-label v-model="asinInput" label="NOT ASIN" />
|
||||||
|
<ui-btn small color="primary" class="mt-5 ml-2" @click="findChapters">Find</ui-btn>
|
||||||
|
</div>
|
||||||
|
<div v-else class="w-full p-4">
|
||||||
|
<p class="mb-4">Duration found: {{ chapterData.runtimeLengthSec }}</p>
|
||||||
|
<div v-if="chapterData.runtimeLengthSec > mediaDuration" class="w-full bg-error bg-opacity-25 p-4 text-center mb-2 rounded border border-white border-opacity-10 text-gray-100 text-sm">
|
||||||
|
<p>Chapter data invalid duration<br />Your media duration is shorter than duration found</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex py-0.5 text-xs font-semibold uppercase text-gray-300 mb-1">
|
||||||
|
<div class="w-24 px-2">Start</div>
|
||||||
|
<div class="flex-grow px-2">Title</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full max-h-80 overflow-y-auto my-2">
|
||||||
|
<div v-for="(chapter, index) in chapterData.chapters" :key="index" class="flex py-0.5 text-xs" :class="chapter.startOffsetSec > mediaDuration ? 'bg-error bg-opacity-20' : chapter.startOffsetSec + chapter.lengthMs / 1000 > mediaDuration ? 'bg-warning bg-opacity-20' : index % 2 === 0 ? 'bg-primary bg-opacity-30' : ''">
|
||||||
|
<div class="w-24 min-w-24 px-2">
|
||||||
|
<p class="font-mono">{{ $secondsToTimestamp(chapter.startOffsetSec) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow px-2">
|
||||||
|
<p class="truncate max-w-sm">{{ chapter.title }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex pt-2">
|
||||||
|
<div class="flex-grow" />
|
||||||
|
<ui-btn small color="success" @click="applyChapterData">Apply Chapters</ui-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</modals-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -168,6 +218,7 @@ export default {
|
|||||||
asinInput: null,
|
asinInput: null,
|
||||||
findingChapters: false,
|
findingChapters: false,
|
||||||
showFindChaptersModal: false,
|
showFindChaptersModal: false,
|
||||||
|
showImportOverdriveMediaMarkersModal: false,
|
||||||
chapterData: null
|
chapterData: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -190,6 +241,12 @@ export default {
|
|||||||
mediaDuration() {
|
mediaDuration() {
|
||||||
return this.media.duration
|
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() {
|
chapters() {
|
||||||
return this.media.chapters || []
|
return this.media.chapters || []
|
||||||
},
|
},
|
||||||
@ -207,6 +264,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
editItem() {
|
||||||
this.$store.commit('showEditModal', this.libraryItem)
|
this.$store.commit('showEditModal', this.libraryItem)
|
||||||
},
|
},
|
||||||
@ -392,7 +456,7 @@ export default {
|
|||||||
this.$toast.error(data.error)
|
this.$toast.error(data.error)
|
||||||
this.showFindChaptersModal = false
|
this.showFindChaptersModal = false
|
||||||
} else {
|
} else {
|
||||||
console.log('Chapter data', data)
|
console.log('Chapter data', JSON.stringify(data))
|
||||||
this.chapterData = data
|
this.chapterData = data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -402,9 +466,41 @@ export default {
|
|||||||
this.$toast.error('Failed to find chapters')
|
this.$toast.error('Failed to find chapters')
|
||||||
this.showFindChaptersModal = false
|
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() {
|
mounted() {
|
||||||
|
this.checkForOverdriveMediaMarkers()
|
||||||
|
var dismissed = false
|
||||||
this.asinInput = this.mediaMetadata.asin || null
|
this.asinInput = this.mediaMetadata.asin || null
|
||||||
this.newChapters = this.chapters.map((c) => ({ ...c }))
|
this.newChapters = this.chapters.map((c) => ({ ...c }))
|
||||||
if (!this.newChapters.length) {
|
if (!this.newChapters.length) {
|
||||||
|
Loading…
Reference in New Issue
Block a user