2022-05-02 18:48:00 -05:00
< template >
< div id = "page-wrapper" class = "bg-bg page p-8 overflow-auto relative" : class = "streamLibraryItem ? 'streaming' : ''" >
2022-10-02 11:53:53 -05:00
< div class = "flex items-center justify-center mb-6" >
2022-05-02 18:48:00 -05:00
< div class = "w-full max-w-2xl" >
2022-11-07 18:27:17 -06:00
< p class = "text-2xl mb-2" > { { $strings . HeaderAudiobookTools } } < / p >
2022-10-02 11:53:53 -05:00
< / div >
< div class = "w-full max-w-2xl" >
< div class = "flex justify-end" >
< ui-dropdown v-model = "selectedTool" :items="availableTools" :disabled="processing" class="max-w-sm" @input="selectedToolUpdated" / >
< / div >
< / div >
< / div >
2023-02-20 10:34:40 -05:00
< div v-if = "isM4BorEmbedTool" >
< div class = "flex justify-center" >
< div class = "w-full max-w-2xl" >
< p class = "text-xl mb-1" > { { $strings . HeaderMetadataToEmbed } } < / p >
< p class = "mb-2 text-base text-gray-300" > audiobookshelf uses < a href = "https://github.com/sandreas/tone" target = "_blank" class = "hover:underline text-blue-400 hover:text-blue-300" > tone < / a > to write metadata . < / p >
< / div >
2022-05-02 18:48:00 -05:00
< div class = "w-full max-h-72 overflow-auto" >
2022-09-25 15:56:06 -05:00
< template v-for = "(value, key, index) in toneObject" >
< div :key = "key" class = "flex py-1 px-4 text-sm" : class = "index % 2 === 0 ? 'bg-primary bg-opacity-25' : ''" >
< div class = "w-1/3 font-semibold" > { { key } } < / div >
2022-05-02 18:48:00 -05:00
< div class = "w-2/3" >
2022-09-25 15:56:06 -05:00
{ { value } }
2022-05-02 18:48:00 -05:00
< / div >
< / div >
< / template >
< / div >
< / div >
2022-09-25 15:56:06 -05:00
< div class = "w-full max-w-2xl border border-white border-opacity-10 bg-bg mx-2" >
2022-10-02 11:53:53 -05:00
< div class = "flex py-2 px-4 bg-primary bg-opacity-25" >
2022-11-08 17:10:08 -06:00
< div class = "flex-grow text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelChapterTitle } } < / div >
< div class = "w-24 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelStart } } < / div >
< div class = "w-24 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelEnd } } < / div >
2022-05-02 18:48:00 -05:00
< / div >
< div class = "w-full max-h-72 overflow-auto" >
2022-11-08 17:10:08 -06:00
< p v-if = "!metadataChapters.length" class="py-5 text-center text-gray-200" > {{ $ strings.MessageNoChapters }} < / p >
2022-05-02 18:48:00 -05:00
< template v-for = "(chapter, index) in metadataChapters" >
2022-10-02 14:16:17 -05:00
< div :key = "index" class = "flex py-1 px-4 text-sm" : class = "index % 2 === 1 ? 'bg-primary bg-opacity-25' : ''" >
2022-05-02 18:48:00 -05:00
< div class = "flex-grow font-semibold" > { { chapter . title } } < / div >
< div class = "w-24" >
2022-09-25 15:56:06 -05:00
{ { $secondsToTimestamp ( chapter . start ) } }
2022-05-02 18:48:00 -05:00
< / div >
< div class = "w-24" >
2022-09-25 15:56:06 -05:00
{ { $secondsToTimestamp ( chapter . end ) } }
2022-05-02 18:48:00 -05:00
< / div >
< / div >
< / template >
< / div >
< / div >
< / div >
< div class = "w-full h-px bg-white bg-opacity-10 my-8" / >
< div class = "w-full max-w-4xl mx-auto" >
2023-04-02 16:13:18 -05:00
<!-- queued alert -- >
< widgets-alert v-if = "isMetadataEmbedQueued" type="warning" class="mb-4" >
< p class = "text-lg" > Audiobook is queued for metadata embed ( { { queuedEmbedLIds . length } } in queue ) < / p >
< / widgets-alert >
<!-- metadata embed action buttons -- >
< div v -else -if = " isEmbedTool " class = "w-full flex justify-end items-center mb-4" >
< ui-checkbox v-if = "!isTaskFinished" v-model="shouldBackupAudioFiles" :disabled="processing" label="Backup audio files" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" @input="toggleBackupAudioFiles" / >
2023-01-07 15:16:52 -06:00
< div class = "flex-grow" / >
2023-04-02 16:13:18 -05:00
< ui-btn v-if = "!isTaskFinished" color="primary" :loading="processing" @click.stop="embedClick" > {{ $ strings.ButtonStartMetadataEmbed }} < / ui -btn >
2022-11-08 17:10:08 -06:00
< p v -else class = "text-success text-lg font-semibold" > { { $strings . MessageEmbedFinished } } < / p >
2022-05-02 18:48:00 -05:00
< / div >
2023-04-02 16:13:18 -05:00
<!-- m4b embed action buttons -- >
2022-12-19 17:13:04 -06:00
< div v -else class = "w-full flex items-center mb-4" >
< button :disabled = "processing" class = "text-sm uppercase text-gray-200 flex items-center pt-px pl-1 pr-2 hover:bg-white/5 rounded-md" @ click = "showEncodeOptions = !showEncodeOptions" >
< span class = "material-icons text-xl" > { { showEncodeOptions ? 'check_box' : 'check_box_outline_blank' } } < / span > < span class = "pl-1" > Use Advanced Options < / span >
< / button >
< div class = "flex-grow" / >
2022-11-08 17:10:08 -06:00
< ui-btn v-if = "!isTaskFinished && processing" color="error" :loading="isCancelingEncode" class="mr-2" @click.stop="cancelEncodeClick" > {{ $ strings.ButtonCancelEncode }} < / ui -btn >
< ui-btn v-if = "!isTaskFinished" color="primary" :loading="processing" @click.stop="encodeM4bClick" > {{ $ strings.ButtonStartM4BEncode }} < / ui -btn >
< p v -else -if = " taskFailed " class = "text-error text-lg font-semibold" > { { $strings . MessageM4BFailed } } { { taskError } } < / p >
< p v -else class = "text-success text-lg font-semibold" > { { $strings . MessageM4BFinished } } < / p >
2022-09-25 15:56:06 -05:00
< / div >
2022-10-02 11:53:53 -05:00
2023-04-02 16:13:18 -05:00
<!-- advanced encoding options -- >
2022-12-19 17:13:04 -06:00
< div v-if = "isM4BTool" class="overflow-hidden" >
< transition name = "slide" >
< div v-if = "showEncodeOptions" class="mb-4 pb-4 border-b border-white/10" >
< div class = "flex flex-wrap -mx-2" >
< ui-text-input-with-label ref = "bitrateInput" v-model = "encodingOptions.bitrate" :disabled="processing || isTaskFinished" :label="'Audio Bitrate (e.g. 64k)'" class="m-2 max-w-40" / >
< ui-text-input-with-label ref = "channelsInput" v-model = "encodingOptions.channels" :disabled="processing || isTaskFinished" :label="'Audio Channels (1 or 2)'" class="m-2 max-w-40" / >
< ui-text-input-with-label ref = "codecInput" v-model = "encodingOptions.codec" :disabled="processing || isTaskFinished" :label="'Audio Codec'" class="m-2 max-w-40" / >
< / div >
< p class = "text-sm text-warning" > Warning : Do not update these settings unless you are familiar with ffmpeg encoding options . < / p >
2023-02-20 10:34:40 -05:00
< / div >
2022-05-02 18:48:00 -05:00
< / div >
2023-02-20 10:34:40 -05:00
< div class = "w-full max-w-2xl border border-white border-opacity-10 bg-bg mx-2" >
< div class = "flex py-2 px-4 bg-primary bg-opacity-25" >
< div class = "flex-grow text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelChapterTitle } } < / div >
< div class = "w-24 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelStart } } < / div >
< div class = "w-24 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelEnd } } < / div >
< / div >
< div class = "w-full max-h-72 overflow-auto" >
< p v-if = "!metadataChapters.length" class="py-5 text-center text-gray-200" > {{ $ strings.MessageNoChapters }} < / p >
< template v-for = "(chapter, index) in metadataChapters" >
< div :key = "index" class = "flex py-1 px-4 text-sm" : class = "index % 2 === 1 ? 'bg-primary bg-opacity-25' : ''" >
< div class = "flex-grow font-semibold" > { { chapter . title } } < / div >
< div class = "w-24" >
{ { $secondsToTimestamp ( chapter . start ) } }
< / div >
< div class = "w-24" >
{ { $secondsToTimestamp ( chapter . end ) } }
< / div >
2022-05-02 18:48:00 -05:00
< / div >
2023-02-20 10:34:40 -05:00
< / template >
< / div >
2022-05-02 18:48:00 -05:00
< / div >
< / div >
2023-02-20 10:34:40 -05:00
< div class = "w-full h-px bg-white bg-opacity-10 my-8" / >
2022-05-02 18:48:00 -05:00
2023-02-20 10:34:40 -05:00
< div class = "w-full max-w-4xl mx-auto" >
< div v-if = "isEmbedTool" class="w-full flex justify-end items-center mb-4" >
< ui-checkbox v-if = "!isFinished" v-model="shouldBackupAudioFiles" label="Backup audio files" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" @input="toggleBackupAudioFiles" / >
2023-01-07 15:16:52 -06:00
2023-02-20 10:34:40 -05:00
< div class = "flex-grow" / >
2023-01-07 15:16:52 -06:00
2023-02-20 10:34:40 -05:00
< ui-btn v-if = "!isFinished" color="primary" :loading="processing" @click.stop="embedClick" > {{ $ strings.ButtonStartMetadataEmbed }} < / ui -btn >
< p v -else class = "text-success text-lg font-semibold" > { { $strings . MessageEmbedFinished } } < / p >
< / div >
< div v -else class = "w-full flex items-center mb-4" >
< button :disabled = "processing" class = "text-sm uppercase text-gray-200 flex items-center pt-px pl-1 pr-2 hover:bg-white/5 rounded-md" @ click = "showEncodeOptions = !showEncodeOptions" >
< span class = "material-icons text-xl" > { { showEncodeOptions ? 'check_box' : 'check_box_outline_blank' } } < / span > < span class = "pl-1" > Use Advanced Options < / span >
< / button >
2022-12-19 17:13:04 -06:00
2023-02-20 10:34:40 -05:00
< div class = "flex-grow" / >
2022-12-19 17:13:04 -06:00
2023-02-20 10:34:40 -05:00
< ui-btn v-if = "!isTaskFinished && processing" color="error" :loading="isCancelingEncode" class="mr-2" @click.stop="cancelEncodeClick" > {{ $ strings.ButtonCancelEncode }} < / ui -btn >
< ui-btn v-if = "!isTaskFinished" color="primary" :loading="processing" @click.stop="encodeM4bClick" > {{ $ strings.ButtonStartM4BEncode }} < / ui -btn >
< p v -else -if = " taskFailed " class = "text-error text-lg font-semibold" > { { $strings . MessageM4BFailed } } { { taskError } } < / p >
< p v -else class = "text-success text-lg font-semibold" > { { $strings . MessageM4BFinished } } < / p >
< / div >
2022-10-02 11:53:53 -05:00
2023-02-20 10:34:40 -05:00
< div v-if = "isM4BTool" class="overflow-hidden" >
< transition name = "slide" >
< div v-if = "showEncodeOptions" class="mb-4 pb-4 border-b border-white/10" >
< div class = "flex flex-wrap -mx-2" >
< ui-text-input-with-label ref = "bitrateInput" v-model = "encodingOptions.bitrate" :disabled="processing || isTaskFinished" :label="'Audio Bitrate (e.g. 64k)'" class="m-2 max-w-40" / >
< ui-text-input-with-label ref = "channelsInput" v-model = "encodingOptions.channels" :disabled="processing || isTaskFinished" :label="'Audio Channels (1 or 2)'" class="m-2 max-w-40" / >
< ui-text-input-with-label ref = "codecInput" v-model = "encodingOptions.codec" :disabled="processing || isTaskFinished" :label="'Audio Codec'" class="m-2 max-w-40" / >
< / div >
< p class = "text-sm text-warning" > Warning : Do not update these settings unless you are familiar with ffmpeg encoding options . < / p >
2022-12-19 17:13:04 -06:00
< / div >
2023-02-20 10:34:40 -05:00
< / transition >
< / div >
< div class = "mb-4" >
< div v-if = "isEmbedTool" class="flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" > Metadata will be embedded in the audio tracks inside your audiobook folder . < / p >
< / div >
< div v -else class = "flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" >
Finished M4B will be put into your audiobook folder at < span class = "rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono" > ... / { { libraryItemRelPath } } / < / span > .
< / p >
2022-12-19 17:13:04 -06:00
< / div >
2023-02-20 10:34:40 -05:00
< div v-if = "shouldBackupAudioFiles || isM4BTool" class="flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" >
A backup of your original audio files will be stored in < span class = "rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono" > / metadata / cache / items / { { libraryItemId } } / < / span > . Make sure to periodically purge items cache .
< / p >
< / div >
< div v-if = "isEmbedTool && audioFiles.length > 1" class="flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" > Chapters are not embedded in multi - track audiobooks . < / p >
< / div >
< div v-if = "isM4BTool" class="flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" > Encoding can take up to 30 minutes . < / p >
< / div >
< div v-if = "isM4BTool" class="flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" > If you have the watcher disabled you will need to re - scan this audiobook afterwards . < / p >
< / div >
< div class = "flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
< p class = "text-gray-200 ml-2" > Once the task is started you can navigate away from this page . < / p >
< / div >
2022-10-02 11:53:53 -05:00
< / div >
2023-02-20 10:34:40 -05:00
< / div >
2022-10-02 11:53:53 -05:00
2023-02-20 10:34:40 -05:00
< div class = "w-full max-w-4xl mx-auto" >
< p class = "mb-2 font-semibold" > { { $strings . HeaderAudioTracks } } < / p >
< div class = "w-full mx-auto border border-white border-opacity-10 bg-bg" >
< div class = "flex py-2 px-4 bg-primary bg-opacity-25" >
< div class = "w-10 text-xs font-semibold text-gray-200" > # < / div >
< div class = "flex-grow text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelFilename } } < / div >
< div class = "w-16 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelSize } } < / div >
< div class = "w-24" > < / div >
< / div >
< template v-for = "file in audioFiles" >
< div :key = "file.index" class = "flex py-2 px-4 text-sm" : class = "file.index % 2 === 0 ? 'bg-primary bg-opacity-25' : ''" >
< div class = "w-10" > { { file . index } } < / div >
< div class = "flex-grow" >
{ { file . metadata . filename } }
< / div >
< div class = "w-16 font-mono text-gray-200" >
{ { $bytesPretty ( file . metadata . size ) } }
< / div >
< div class = "w-24" >
< div class = "flex justify-center" >
< span v-if = "audiofilesFinished[file.ino]" class="material-icons text-xl text-success leading-none" > check_circle < / span >
< div v -else -if = " audiofilesEncoding [ file.ino ] " >
< widgets-loading-spinner / >
< / div >
< / div >
< / div >
< / div >
< / template >
2022-10-02 11:53:53 -05:00
< / div >
< / div >
< / div >
2023-02-20 10:34:40 -05:00
< div v-if = "isRenameTool" >
< div class = "flex justify-left" >
< div class = "w-full max-w-2xl" >
< p class = "text-xl mb-1" > { { $strings . HeaderRenameTool } } < / p >
< div class = "flex items-start mb-2" >
< ui-text-input-with-label ref = "userRenameFormat" v-model = "renameFormat" :label="'Format for Rename'" class="m-2 max-w-100" / >
< / div >
< div class = "flex items-start mb-2" >
< ui-btn color = "primary" :loading = "processing" @click.stop ="previewRenameClick" > { { $strings . ButtonPreviewRename } } < / ui-btn >
< / div >
< div class = "flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
{ { $strings . LabelCurrent } } { { $strings . LabelPath } } : < span ref = "currentRelPath" class = "rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono" > ... { { this . directorySeperatorChar } } { { libraryItemRelPath } } { { this . directorySeperatorChar } } < / span >
< / div >
< div class = "flex items-start mb-2" >
< span class = "material-icons text-base text-warning pt-1" > star < / span >
{ { $strings . LabelNew } } { { $strings . LabelPath } } : < span ref = "newFolderRelPath" class = "rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono" > ... { { this . directorySeperatorChar } } { { libraryItemRelPath } } { { this . directorySeperatorChar } } < / span >
< / div >
< div class = "flex items-start mb-2" >
< ui-btn ref = "executeRenameButton" :loading = "processing" color = "primary" @click.stop ="renameClick" > { { $strings . ButtonExecuteRename } } < / ui-btn >
< / div >
< div class = "flex items-start mb-2" >
< span ref = "renameStatus" class = "rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono" > < / span >
< / div >
< / div >
< div class = "w-full max-w-2xl" >
2022-10-02 11:53:53 -05:00
< div class = "flex py-2 px-4 bg-primary bg-opacity-25" >
2023-02-20 10:34:40 -05:00
< div class = "w-1/3 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelKey } } < / div >
< div class = "w-2/3 text-xs font-semibold uppercase text-gray-200" > { { $strings . LabelValue } } < / div >
2022-05-02 18:48:00 -05:00
< / div >
2023-02-20 10:34:40 -05:00
< div class = "flex py-1 px-4 text-sm" >
< div class = "w-1/3 font-semibold" > / < / div >
< div class = "w-2/3" >
{ { $strings . LabelDirectorySeperator } }
2022-05-02 18:48:00 -05:00
< / div >
2023-02-20 10:34:40 -05:00
< / div >
< template v-for = "(value, key, index) in sampleFormatObject" >
< div :key = "key" class = "flex py-1 px-4 text-sm" : class = "index % 2 === 0 ? 'bg-primary bg-opacity-25' : ''" >
< div class = "w-1/3 font-semibold" > $ { { key . replace ( 'lbr' , '[' ) . replace ( 'rbr' , ']' ) } } < / div >
< div class = "w-2/3" >
{ { value } }
2022-05-02 18:48:00 -05:00
< / div >
< / div >
< / template >
2023-02-20 10:34:40 -05:00
< / div >
2022-05-02 18:48:00 -05:00
< / div >
< / div >
2023-02-20 10:34:40 -05:00
< / div >
2022-05-02 18:48:00 -05:00
< / template >
< script >
export default {
async asyncData ( { store , params , app , redirect , route } ) {
if ( ! store . state . user . user ) {
return redirect ( ` /login?redirect= ${ route . path } ` )
}
if ( ! store . getters [ 'user/getIsAdminOrUp' ] ) {
return redirect ( '/?error=unauthorized' )
}
2023-01-07 15:16:52 -06:00
const libraryItem = await app . $axios . $get ( ` /api/items/ ${ params . id } ?expanded=1 ` ) . catch ( ( error ) => {
2022-05-02 18:48:00 -05:00
console . error ( 'Failed' , error )
return false
} )
if ( ! libraryItem ) {
console . error ( 'Not found...' , params . id )
return redirect ( '/?error=not found' )
}
if ( libraryItem . mediaType !== 'book' ) {
console . error ( 'Invalid media type' )
return redirect ( '/?error=invalid media type' )
}
if ( ! libraryItem . media . audioFiles . length ) {
cnosole . error ( 'No audio files' )
return redirect ( '/?error=no audio files' )
}
2023-04-02 16:13:18 -05:00
2022-05-02 18:48:00 -05:00
return {
libraryItem
}
} ,
data ( ) {
return {
2022-10-02 14:16:17 -05:00
processing : false ,
2022-05-02 18:48:00 -05:00
audiofilesEncoding : { } ,
audiofilesFinished : { } ,
2022-10-02 11:53:53 -05:00
toneObject : null ,
2022-10-02 14:31:04 -05:00
selectedTool : 'embed' ,
2022-12-19 17:13:04 -06:00
isCancelingEncode : false ,
showEncodeOptions : false ,
2023-01-07 15:16:52 -06:00
shouldBackupAudioFiles : true ,
2022-12-19 17:13:04 -06:00
encodingOptions : {
bitrate : '64k' ,
channels : '2' ,
codec : 'aac'
2023-02-20 10:34:40 -05:00
} ,
renameFormat : '' ,
sampleFormatObject : null ,
directorySeperatorChar : '/'
2022-05-02 18:48:00 -05:00
}
} ,
2022-10-02 14:16:17 -05:00
watch : {
task : {
handler ( newVal ) {
if ( newVal ) {
this . taskUpdated ( newVal )
}
}
}
} ,
2022-05-02 18:48:00 -05:00
computed : {
2022-12-19 17:13:04 -06:00
isEmbedTool ( ) {
return this . selectedTool === 'embed'
} ,
isM4BTool ( ) {
return this . selectedTool === 'm4b'
} ,
2023-02-20 10:34:40 -05:00
isM4BorEmbedTool ( ) {
return this . isM4BTool || this . isEmbedTool
} ,
isRenameTool ( ) {
return this . selectedTool === 'renamer'
} ,
2022-05-02 18:48:00 -05:00
libraryItemId ( ) {
return this . libraryItem . id
} ,
2022-10-02 11:53:53 -05:00
libraryItemRelPath ( ) {
return this . libraryItem . relPath
} ,
2022-05-02 18:48:00 -05:00
media ( ) {
return this . libraryItem . media || { }
} ,
mediaMetadata ( ) {
return this . media . metadata || { }
} ,
audioFiles ( ) {
2022-10-02 11:53:53 -05:00
return ( this . media . audioFiles || [ ] ) . filter ( ( af ) => ! af . exclude && ! af . invalid )
} ,
isSingleM4b ( ) {
return this . audioFiles . length === 1 && this . audioFiles [ 0 ] . metadata . ext . toLowerCase ( ) === '.m4b'
2022-05-02 18:48:00 -05:00
} ,
streamLibraryItem ( ) {
return this . $store . state . streamLibraryItem
} ,
2023-02-20 10:34:40 -05:00
defaultRenameString ( ) {
return this . $store . state . defaultRenameString
} ,
2022-05-02 18:48:00 -05:00
metadataChapters ( ) {
2022-10-02 08:44:38 -05:00
return this . media . chapters || [ ]
2022-10-02 11:53:53 -05:00
} ,
availableTools ( ) {
2023-02-20 10:34:40 -05:00
var tools = [
{ value : 'embed' , text : 'Embed Metadata' } ,
{ value : 'renamer' , text : 'Rename Folder' } ,
{ value : 'm4b' , text : 'M4B Encoder' }
]
2022-10-02 11:53:53 -05:00
if ( this . isSingleM4b ) {
2023-02-20 10:34:40 -05:00
tools . pop ( )
2022-10-02 11:53:53 -05:00
}
2023-02-20 10:34:40 -05:00
return tools
2022-10-02 14:16:17 -05:00
} ,
taskFailed ( ) {
return this . isTaskFinished && this . task . isFailed
} ,
taskError ( ) {
return this . taskFailed ? this . task . error || 'Unknown Error' : null
} ,
isTaskFinished ( ) {
return this . task && this . task . isFinished
} ,
2023-04-02 16:13:18 -05:00
tasks ( ) {
return this . $store . getters [ 'tasks/getTasksByLibraryItemId' ] ( this . libraryItemId )
} ,
embedTask ( ) {
return this . tasks . find ( ( t ) => t . action === 'embed-metadata' )
} ,
encodeTask ( ) {
return this . tasks . find ( ( t ) => t . action === 'encode-m4b' )
} ,
2022-10-02 14:16:17 -05:00
task ( ) {
2023-04-02 16:13:18 -05:00
if ( this . isEmbedTool ) return this . embedTask
else if ( this . isM4BTool ) return this . encodeTask
return null
2022-10-02 14:16:17 -05:00
} ,
taskRunning ( ) {
return this . task && ! this . task . isFinished
2023-04-02 16:13:18 -05:00
} ,
queuedEmbedLIds ( ) {
return this . $store . state . tasks . queuedEmbedLIds || [ ]
} ,
isMetadataEmbedQueued ( ) {
return this . queuedEmbedLIds . some ( ( lid ) => lid === this . libraryItemId )
2022-05-02 18:48:00 -05:00
}
} ,
methods : {
2023-01-07 15:16:52 -06:00
toggleBackupAudioFiles ( val ) {
localStorage . setItem ( 'embedMetadataShouldBackup' , val ? 1 : 0 )
} ,
2022-10-02 14:31:04 -05:00
cancelEncodeClick ( ) {
this . isCancelingEncode = true
this . $axios
2022-11-19 13:28:06 -06:00
. $delete ( ` /api/tools/item/ ${ this . libraryItemId } /encode-m4b ` )
2022-10-02 14:31:04 -05:00
. then ( ( ) => {
this . $toast . success ( 'Encode canceled' )
} )
. catch ( ( error ) => {
console . error ( 'Failed to cancel encode' , error )
this . $toast . error ( 'Failed to cancel encode' )
} )
. finally ( ( ) => {
this . isCancelingEncode = false
} )
} ,
2022-10-02 11:53:53 -05:00
encodeM4bClick ( ) {
2022-12-19 17:13:04 -06:00
if ( this . $refs . bitrateInput ) this . $refs . bitrateInput . blur ( )
if ( this . $refs . channelsInput ) this . $refs . channelsInput . blur ( )
if ( this . $refs . codecInput ) this . $refs . codecInput . blur ( )
let queryStr = ''
if ( this . showEncodeOptions ) {
const options = [ ]
if ( this . encodingOptions . bitrate ) options . push ( ` bitrate= ${ this . encodingOptions . bitrate } ` )
if ( this . encodingOptions . channels ) options . push ( ` channels= ${ this . encodingOptions . channels } ` )
if ( this . encodingOptions . codec ) options . push ( ` codec= ${ this . encodingOptions . codec } ` )
if ( options . length ) {
queryStr = ` ? ${ options . join ( '&' ) } `
}
}
2022-10-02 11:53:53 -05:00
this . processing = true
this . $axios
2022-12-19 17:13:04 -06:00
. $post ( ` /api/tools/item/ ${ this . libraryItemId } /encode-m4b ${ queryStr } ` )
2022-10-02 11:53:53 -05:00
. then ( ( ) => {
2022-10-02 14:16:17 -05:00
console . log ( 'Ab m4b merge started' )
2022-10-02 11:53:53 -05:00
} )
. catch ( ( error ) => {
var errorMsg = error . response ? error . response . data || 'Unknown Error' : 'Unknown Error'
this . $toast . error ( errorMsg )
2023-04-02 16:13:18 -05:00
this . processing = false
2022-10-02 11:53:53 -05:00
} )
} ,
2022-09-25 15:56:06 -05:00
embedClick ( ) {
const payload = {
message : ` Are you sure you want to embed metadata in ${ this . audioFiles . length } audio files? ` ,
callback : ( confirmed ) => {
if ( confirmed ) {
this . updateAudioFileMetadata ( )
}
} ,
type : 'yesNo'
2022-05-02 18:48:00 -05:00
}
2022-09-25 15:56:06 -05:00
this . $store . commit ( 'globals/setConfirmPrompt' , payload )
} ,
2023-02-20 10:34:40 -05:00
async previewRenameClick ( ) {
this . processing = true
const renameObject = await this . $axios
. $get ( ` /api/tools/item/ ${ this . libraryItemId } /renameFolder?strFormat= ${ this . renameFormat } ${ this . sampleFormatObject == null ? '&includeSampleTemplate=1' : '' } ` )
. then ( ( renameObject ) => {
return renameObject
} )
. catch ( ( error ) => {
console . error ( 'Failed to Rename' , error )
} )
this . directorySeperatorChar = renameObject . directorySeperatorChar
this . $refs . newFolderRelPath . setHTML ( '...' + this . directorySeperatorChar + renameObject . newRelativeDirectory + this . directorySeperatorChar )
if ( renameObject . templateSample ) {
this . sampleFormatObject = renameObject . templateSample
}
this . processing = false
} ,
async renameClick ( ) {
const renameObject = await this . $axios
. $post ( ` /api/tools/item/ ${ this . libraryItemId } /renameFolder?strFormat= ${ this . renameFormat } ` )
. then ( ( renameObject ) => {
return renameObject
} )
. catch ( ( error ) => {
console . error ( 'Failed to Rename' , error )
} )
if ( renameObject . success ) {
this . $refs . renameStatus . setHTML ( 'Folder for Book updated to ...' + this . directorySeperatorChar + renameObject . details . newRelativeDirectory + this . directorySeperatorChar + ' from ' + renameObject . details . oldRelativeDirectory )
this . $refs . currentRelPath . setHTML ( '...' + this . directorySeperatorChar + renameObject . details . newRelativeDirectory + this . directorySeperatorChar )
}
else {
this . $refs . renameStatus . setHTML ( 'Failed to Rename: ' + JSON . stringify ( renameObject . details ) )
}
this . processing = false
} ,
2022-09-25 15:56:06 -05:00
updateAudioFileMetadata ( ) {
2022-10-02 11:53:53 -05:00
this . processing = true
2022-09-25 15:56:06 -05:00
this . $axios
2023-01-07 15:16:52 -06:00
. $post ( ` /api/tools/item/ ${ this . libraryItemId } /embed-metadata?backup= ${ this . shouldBackupAudioFiles ? 1 : 0 } ` )
2022-09-25 15:56:06 -05:00
. then ( ( ) => {
console . log ( 'Audio metadata encode started' )
} )
. catch ( ( error ) => {
console . error ( 'Audio metadata encode failed' , error )
2022-10-02 11:53:53 -05:00
this . processing = false
2022-09-25 15:56:06 -05:00
} )
2022-05-02 18:48:00 -05:00
} ,
audiofileMetadataStarted ( data ) {
if ( data . libraryItemId !== this . libraryItemId ) return
this . $set ( this . audiofilesEncoding , data . ino , true )
} ,
audiofileMetadataFinished ( data ) {
if ( data . libraryItemId !== this . libraryItemId ) return
this . $set ( this . audiofilesEncoding , data . ino , false )
this . $set ( this . audiofilesFinished , data . ino , true )
2022-09-25 15:56:06 -05:00
} ,
2022-10-02 11:53:53 -05:00
selectedToolUpdated ( ) {
let newurl = window . location . protocol + '//' + window . location . host + window . location . pathname + ` ?tool= ${ this . selectedTool } `
window . history . replaceState ( { path : newurl } , '' , newurl )
2023-02-20 10:34:40 -05:00
if ( this . selectedTool == 'renamer' ) {
this . previewRenameClick ( )
}
2022-10-02 11:53:53 -05:00
} ,
init ( ) {
this . fetchToneObject ( )
if ( this . $route . query . tool === 'm4b' ) {
if ( this . availableTools . some ( ( t ) => t . value === 'm4b' ) ) {
this . selectedTool = 'm4b'
} else {
this . selectedToolUpdated ( )
}
}
2023-02-20 10:34:40 -05:00
else if ( this . $route . query . tool === 'renamer' ) {
if ( this . availableTools . some ( ( t ) => t . value === 'renamer' ) ) {
this . previewRenameClick ( )
this . selectedTool = 'renamer'
} else {
this . selectedToolUpdated ( )
}
}
2022-10-02 14:16:17 -05:00
if ( this . task ) this . taskUpdated ( this . task )
2023-01-07 15:16:52 -06:00
const shouldBackupAudioFiles = localStorage . getItem ( 'embedMetadataShouldBackup' )
this . shouldBackupAudioFiles = shouldBackupAudioFiles != 0
2023-02-20 10:34:40 -05:00
const defaultRenameString = localStorage . getItem ( 'defaultRenameString' )
this . renameFormat = defaultRenameString ? defaultRenameString : '$authorName/$bookName'
debugger
2022-10-02 11:53:53 -05:00
} ,
2022-09-25 15:56:06 -05:00
fetchToneObject ( ) {
this . $axios
. $get ( ` /api/items/ ${ this . libraryItemId } /tone-object ` )
. then ( ( toneObject ) => {
delete toneObject . CoverFile
this . toneObject = toneObject
} )
. catch ( ( error ) => {
console . error ( 'Failed to fetch tone object' , error )
} )
2022-10-02 14:16:17 -05:00
} ,
taskUpdated ( task ) {
this . processing = ! task . isFinished
2022-05-02 18:48:00 -05:00
}
} ,
mounted ( ) {
2022-10-02 11:53:53 -05:00
this . init ( )
2022-05-02 18:48:00 -05:00
this . $root . socket . on ( 'audiofile_metadata_started' , this . audiofileMetadataStarted )
this . $root . socket . on ( 'audiofile_metadata_finished' , this . audiofileMetadataFinished )
} ,
beforeDestroy ( ) {
this . $root . socket . off ( 'audiofile_metadata_started' , this . audiofileMetadataStarted )
this . $root . socket . off ( 'audiofile_metadata_finished' , this . audiofileMetadataFinished )
}
}
< / script >