mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-05-18 01:15:31 +02:00
Merge branch 'master' into auth_passportjs
This commit is contained in:
commit
8d0064763c
@ -287,26 +287,37 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
batchDeleteClick() {
|
batchDeleteClick() {
|
||||||
const audiobookText = this.numMediaItemsSelected > 1 ? `these ${this.numMediaItemsSelected} items` : 'this item'
|
const payload = {
|
||||||
const confirmMsg = `Are you sure you want to remove ${audiobookText}?\n\n*Does not delete your files, only removes the items from Audiobookshelf`
|
message: `This will delete ${this.numMediaItemsSelected} library items from the database and your file system. Are you sure?`,
|
||||||
if (confirm(confirmMsg)) {
|
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.',
|
||||||
this.$store.commit('setProcessingBatch', true)
|
yesButtonText: this.$strings.ButtonDelete,
|
||||||
this.$axios
|
yesButtonColor: 'error',
|
||||||
.$post(`/api/items/batch/delete`, {
|
checkboxDefaultValue: true,
|
||||||
libraryItemIds: this.selectedMediaItems.map((i) => i.id)
|
callback: (confirmed, hardDelete) => {
|
||||||
})
|
if (confirmed) {
|
||||||
.then(() => {
|
this.$store.commit('setProcessingBatch', true)
|
||||||
this.$toast.success('Batch delete success!')
|
|
||||||
this.$store.commit('setProcessingBatch', false)
|
this.$axios
|
||||||
this.$store.commit('globals/resetSelectedMediaItems', [])
|
.$post(`/api/items/batch/delete?hard=${hardDelete ? 1 : 0}`, {
|
||||||
this.$eventBus.$emit('bookshelf_clear_selection')
|
libraryItemIds: this.selectedMediaItems.map((i) => i.id)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.then(() => {
|
||||||
this.$toast.error('Batch delete failed')
|
this.$toast.success('Batch delete success')
|
||||||
console.error('Failed to batch delete', error)
|
this.$store.commit('globals/resetSelectedMediaItems', [])
|
||||||
this.$store.commit('setProcessingBatch', false)
|
this.$eventBus.$emit('bookshelf_clear_selection')
|
||||||
})
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Batch delete failed', error)
|
||||||
|
this.$toast.error('Batch delete failed')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$store.commit('setProcessingBatch', false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 'yesNo'
|
||||||
}
|
}
|
||||||
|
this.$store.commit('globals/setConfirmPrompt', payload)
|
||||||
},
|
},
|
||||||
batchEditClick() {
|
batchEditClick() {
|
||||||
this.$router.push('/batch')
|
this.$router.push('/batch')
|
||||||
|
@ -526,6 +526,14 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.userCanDelete) {
|
||||||
|
items.push({
|
||||||
|
func: 'deleteLibraryItem',
|
||||||
|
text: this.$strings.ButtonDelete
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
},
|
},
|
||||||
_socket() {
|
_socket() {
|
||||||
@ -777,6 +785,35 @@ export default {
|
|||||||
this.store.commit('globals/setSelectedPlaylistItems', [{ libraryItem: this.libraryItem, episode: this.recentEpisode }])
|
this.store.commit('globals/setSelectedPlaylistItems', [{ libraryItem: this.libraryItem, episode: this.recentEpisode }])
|
||||||
this.store.commit('globals/setShowPlaylistsModal', true)
|
this.store.commit('globals/setShowPlaylistsModal', true)
|
||||||
},
|
},
|
||||||
|
deleteLibraryItem() {
|
||||||
|
const payload = {
|
||||||
|
message: 'This will delete the library item from the database and your file system. Are you sure?',
|
||||||
|
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.',
|
||||||
|
yesButtonText: this.$strings.ButtonDelete,
|
||||||
|
yesButtonColor: 'error',
|
||||||
|
checkboxDefaultValue: true,
|
||||||
|
callback: (confirmed, hardDelete) => {
|
||||||
|
if (confirmed) {
|
||||||
|
this.processing = true
|
||||||
|
const axios = this.$axios || this.$nuxt.$axios
|
||||||
|
axios
|
||||||
|
.$delete(`/api/items/${this.libraryItemId}?hard=${hardDelete ? 1 : 0}`)
|
||||||
|
.then(() => {
|
||||||
|
this.$toast.success('Item deleted')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to delete item', error)
|
||||||
|
this.$toast.error('Failed to delete item')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 'yesNo'
|
||||||
|
}
|
||||||
|
this.store.commit('globals/setConfirmPrompt', payload)
|
||||||
|
},
|
||||||
createMoreMenu() {
|
createMoreMenu() {
|
||||||
if (!this.$refs.moreIcon) return
|
if (!this.$refs.moreIcon) return
|
||||||
|
|
||||||
|
118
client/components/modals/AudioFileDataModal.vue
Normal file
118
client/components/modals/AudioFileDataModal.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<modals-modal v-model="show" name="audiofile-data-modal" :width="700" :height="'unset'">
|
||||||
|
<div v-if="audioFile" ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden p-6" style="max-height: 80vh">
|
||||||
|
<p class="text-base text-gray-200">{{ metadata.filename }}</p>
|
||||||
|
|
||||||
|
<div class="w-full h-px bg-white bg-opacity-10 my-4" />
|
||||||
|
|
||||||
|
<ui-text-input-with-label :value="metadata.path" readonly :label="$strings.LabelPath" class="mb-4 text-sm" />
|
||||||
|
|
||||||
|
<div class="flex flex-col sm:flex-row text-sm">
|
||||||
|
<div class="w-full sm:w-1/2">
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelSize }}
|
||||||
|
</p>
|
||||||
|
<p>{{ $bytesPretty(metadata.size) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelDuration }}
|
||||||
|
</p>
|
||||||
|
<p>{{ $secondsToTimestamp(audioFile.duration) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">{{ $strings.LabelFormat }}</p>
|
||||||
|
<p>{{ audioFile.format }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelChapters }}
|
||||||
|
</p>
|
||||||
|
<p>{{ audioFile.chapters?.length || 0 }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="audioFile.embeddedCoverArt" class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelEmbeddedCover }}
|
||||||
|
</p>
|
||||||
|
<p>{{ audioFile.embeddedCoverArt || '' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full sm:w-1/2">
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelCodec }}
|
||||||
|
</p>
|
||||||
|
<p>{{ audioFile.codec }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelChannels }}
|
||||||
|
</p>
|
||||||
|
<p>{{ audioFile.channels }} ({{ audioFile.channelLayout }})</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelBitrate }}
|
||||||
|
</p>
|
||||||
|
<p>{{ $bytesPretty(audioFile.bitRate || 0, 0) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">{{ $strings.LabelTimeBase }}</p>
|
||||||
|
<p>{{ audioFile.timeBase }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="audioFile.language" class="flex mb-1">
|
||||||
|
<p class="w-32 text-black-50">
|
||||||
|
{{ $strings.LabelLanguage }}
|
||||||
|
</p>
|
||||||
|
<p>{{ audioFile.language || '' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full h-px bg-white bg-opacity-10 my-4" />
|
||||||
|
|
||||||
|
<p class="font-bold mb-2">{{ $strings.LabelMetaTags }}</p>
|
||||||
|
|
||||||
|
<div v-for="(value, key) in metaTags" :key="key" class="flex mb-1 text-sm">
|
||||||
|
<p class="w-32 min-w-32 text-black-50 mb-1">
|
||||||
|
{{ key.replace('tag', '') }}
|
||||||
|
</p>
|
||||||
|
<p>{{ value }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</modals-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: Boolean,
|
||||||
|
audioFile: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('input', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata() {
|
||||||
|
return this.audioFile?.metadata || {}
|
||||||
|
},
|
||||||
|
metaTags() {
|
||||||
|
return this.audioFile?.metaTags || {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -7,11 +7,6 @@
|
|||||||
|
|
||||||
<div class="absolute bottom-0 left-0 w-full py-2 md:py-4 bg-bg" :class="isScrollable ? 'box-shadow-md-up' : 'border-t border-white border-opacity-5'">
|
<div class="absolute bottom-0 left-0 w-full py-2 md:py-4 bg-bg" :class="isScrollable ? 'box-shadow-md-up' : 'border-t border-white border-opacity-5'">
|
||||||
<div class="flex items-center px-4">
|
<div class="flex items-center px-4">
|
||||||
<ui-btn v-if="userCanDelete" color="error" type="button" class="h-8 hidden md:block" :padding-x="3" small @click.stop.prevent="removeItem">{{ $strings.ButtonRemove }}</ui-btn>
|
|
||||||
<ui-icon-btn bg-color="error" icon="delete" class="md:hidden" :size="7" icon-font-size="1rem" @click.stop.prevent="removeItem" />
|
|
||||||
|
|
||||||
<div class="flex-grow" />
|
|
||||||
|
|
||||||
<ui-tooltip :disabled="!!quickMatching" :text="$getString('MessageQuickMatchDescription', [libraryProvider])" direction="bottom" class="mr-2 md:mr-4">
|
<ui-tooltip :disabled="!!quickMatching" :text="$getString('MessageQuickMatchDescription', [libraryProvider])" direction="bottom" class="mr-2 md:mr-4">
|
||||||
<ui-btn v-if="userIsAdminOrUp" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">{{ $strings.ButtonQuickMatch }}</ui-btn>
|
<ui-btn v-if="userIsAdminOrUp" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">{{ $strings.ButtonQuickMatch }}</ui-btn>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -20,6 +15,8 @@
|
|||||||
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="!!libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn>
|
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="!!libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
|
<div class="flex-grow" />
|
||||||
|
|
||||||
<!-- desktop -->
|
<!-- desktop -->
|
||||||
<ui-btn @click="save" class="mx-2 hidden md:block">{{ $strings.ButtonSave }}</ui-btn>
|
<ui-btn @click="save" class="mx-2 hidden md:block">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
<ui-btn @click="saveAndClose" class="mx-2 hidden md:block">{{ $strings.ButtonSaveAndClose }}</ui-btn>
|
<ui-btn @click="saveAndClose" class="mx-2 hidden md:block">{{ $strings.ButtonSaveAndClose }}</ui-btn>
|
||||||
@ -77,9 +74,6 @@ export default {
|
|||||||
mediaMetadata() {
|
mediaMetadata() {
|
||||||
return this.media.metadata || {}
|
return this.media.metadata || {}
|
||||||
},
|
},
|
||||||
userCanDelete() {
|
|
||||||
return this.$store.getters['user/getUserCanDelete']
|
|
||||||
},
|
|
||||||
libraryId() {
|
libraryId() {
|
||||||
return this.libraryItem ? this.libraryItem.libraryId : null
|
return this.libraryItem ? this.libraryItem.libraryId : null
|
||||||
},
|
},
|
||||||
@ -184,23 +178,6 @@ export default {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
removeItem() {
|
|
||||||
if (confirm(`Are you sure you want to remove this item?\n\n*Does not delete your files, only removes the item from audiobookshelf`)) {
|
|
||||||
this.isProcessing = true
|
|
||||||
this.$axios
|
|
||||||
.$delete(`/api/items/${this.libraryItemId}`)
|
|
||||||
.then(() => {
|
|
||||||
console.log('Item removed')
|
|
||||||
this.$toast.success('Item Removed')
|
|
||||||
this.$emit('close')
|
|
||||||
this.isProcessing = false
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Remove item failed', error)
|
|
||||||
this.isProcessing = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkIsScrollable() {
|
checkIsScrollable() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
var formWrapper = document.getElementById('formWrapper')
|
var formWrapper = document.getElementById('formWrapper')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full overflow-y-auto overflow-x-hidden px-4 py-6">
|
<div class="w-full h-full overflow-y-auto overflow-x-hidden px-4 py-6">
|
||||||
<tables-library-files-table expanded :files="libraryFiles" :library-item-id="libraryItem.id" :is-missing="isMissing" />
|
<tables-library-files-table expanded :library-item="libraryItem" :is-missing="isMissing" in-modal />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -30,9 +30,6 @@ export default {
|
|||||||
media() {
|
media() {
|
||||||
return this.libraryItem.media || {}
|
return this.libraryItem.media || {}
|
||||||
},
|
},
|
||||||
libraryFiles() {
|
|
||||||
return this.libraryItem.libraryFiles || []
|
|
||||||
},
|
|
||||||
userToken() {
|
userToken() {
|
||||||
return this.$store.getters['user/getToken']
|
return this.$store.getters['user/getToken']
|
||||||
},
|
},
|
||||||
|
@ -3,11 +3,14 @@
|
|||||||
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-gradient-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-gradient-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
||||||
<div ref="content" class="relative text-white" :style="{ height: modalHeight, width: modalWidth }" v-click-outside="clickedOutside">
|
<div ref="content" class="relative text-white" :style="{ height: modalHeight, width: modalWidth }" v-click-outside="clickedOutside">
|
||||||
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
<p class="text-lg mb-8 mt-2 px-1" v-html="message" />
|
<p class="text-lg mb-6 mt-2 px-1" v-html="message" />
|
||||||
|
|
||||||
|
<ui-checkbox v-if="checkboxLabel" v-model="checkboxValue" checkbox-bg="bg" :label="checkboxLabel" label-class="pl-2 text-base" class="mb-6 px-1" />
|
||||||
|
|
||||||
<div class="flex px-1 items-center">
|
<div class="flex px-1 items-center">
|
||||||
<ui-btn v-if="isYesNo" color="primary" @click="nevermind">{{ $strings.ButtonCancel }}</ui-btn>
|
<ui-btn v-if="isYesNo" color="primary" @click="nevermind">{{ $strings.ButtonCancel }}</ui-btn>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="isYesNo" color="success" @click="confirm">{{ $strings.ButtonYes }}</ui-btn>
|
<ui-btn v-if="isYesNo" :color="yesButtonColor" @click="confirm">{{ yesButtonText }}</ui-btn>
|
||||||
<ui-btn v-else color="primary" @click="confirm">{{ $strings.ButtonOk }}</ui-btn>
|
<ui-btn v-else color="primary" @click="confirm">{{ $strings.ButtonOk }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -21,7 +24,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
el: null,
|
el: null,
|
||||||
content: null
|
content: null,
|
||||||
|
checkboxValue: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -57,6 +61,18 @@ export default {
|
|||||||
persistent() {
|
persistent() {
|
||||||
return !!this.confirmPromptOptions.persistent
|
return !!this.confirmPromptOptions.persistent
|
||||||
},
|
},
|
||||||
|
checkboxLabel() {
|
||||||
|
return this.confirmPromptOptions.checkboxLabel
|
||||||
|
},
|
||||||
|
yesButtonText() {
|
||||||
|
return this.confirmPromptOptions.yesButtonText || this.$strings.ButtonYes
|
||||||
|
},
|
||||||
|
yesButtonColor() {
|
||||||
|
return this.confirmPromptOptions.yesButtonColor || 'success'
|
||||||
|
},
|
||||||
|
checkboxDefaultValue() {
|
||||||
|
return !!this.confirmPromptOptions.checkboxDefaultValue
|
||||||
|
},
|
||||||
isYesNo() {
|
isYesNo() {
|
||||||
return this.type === 'yesNo'
|
return this.type === 'yesNo'
|
||||||
},
|
},
|
||||||
@ -84,10 +100,11 @@ export default {
|
|||||||
this.show = false
|
this.show = false
|
||||||
},
|
},
|
||||||
confirm() {
|
confirm() {
|
||||||
if (this.callback) this.callback(true)
|
if (this.callback) this.callback(true, this.checkboxValue)
|
||||||
this.show = false
|
this.show = false
|
||||||
},
|
},
|
||||||
setShow() {
|
setShow() {
|
||||||
|
this.checkboxValue = this.checkboxDefaultValue
|
||||||
this.$eventBus.$emit('showing-prompt', true)
|
this.$eventBus.$emit('showing-prompt', true)
|
||||||
document.body.appendChild(this.el)
|
document.body.appendChild(this.el)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
123
client/components/tables/AudioTracksTableRow.vue
Normal file
123
client/components/tables/AudioTracksTableRow.vue
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<p>{{ track.index }}</p>
|
||||||
|
</td>
|
||||||
|
<td class="font-sans">{{ showFullPath ? track.metadata.path : track.metadata.filename }}</td>
|
||||||
|
<td v-if="!showFullPath" class="hidden lg:table-cell">
|
||||||
|
{{ track.audioFile.codec || '' }}
|
||||||
|
</td>
|
||||||
|
<td v-if="!showFullPath" class="hidden xl:table-cell">
|
||||||
|
{{ $bytesPretty(track.audioFile.bitRate || 0, 0) }}
|
||||||
|
</td>
|
||||||
|
<td class="hidden md:table-cell">
|
||||||
|
{{ $bytesPretty(track.metadata.size) }}
|
||||||
|
</td>
|
||||||
|
<td class="hidden sm:table-cell">
|
||||||
|
{{ $secondsToTimestamp(track.duration) }}
|
||||||
|
</td>
|
||||||
|
<td v-if="contextMenuItems.length" class="text-center">
|
||||||
|
<ui-context-menu-dropdown :items="contextMenuItems" menu-width="110px" @action="contextMenuAction" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
libraryItemId: String,
|
||||||
|
showFullPath: Boolean,
|
||||||
|
track: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
userToken() {
|
||||||
|
return this.$store.getters['user/getToken']
|
||||||
|
},
|
||||||
|
userCanDownload() {
|
||||||
|
return this.$store.getters['user/getUserCanDownload']
|
||||||
|
},
|
||||||
|
userCanDelete() {
|
||||||
|
return this.$store.getters['user/getUserCanDelete']
|
||||||
|
},
|
||||||
|
userIsAdmin() {
|
||||||
|
return this.$store.getters['user/getIsAdminOrUp']
|
||||||
|
},
|
||||||
|
contextMenuItems() {
|
||||||
|
const items = []
|
||||||
|
if (this.userCanDownload) {
|
||||||
|
items.push({
|
||||||
|
text: this.$strings.LabelDownload,
|
||||||
|
action: 'download'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.userCanDelete) {
|
||||||
|
items.push({
|
||||||
|
text: this.$strings.ButtonDelete,
|
||||||
|
action: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.userIsAdmin) {
|
||||||
|
items.push({
|
||||||
|
text: this.$strings.LabelMoreInfo,
|
||||||
|
action: 'more'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
},
|
||||||
|
downloadUrl() {
|
||||||
|
return `${process.env.serverUrl}/s/item/${this.libraryItemId}/${this.$encodeUriPath(this.track.metadata.relPath).replace(/^\//, '')}?token=${this.userToken}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
contextMenuAction(action) {
|
||||||
|
if (action === 'delete') {
|
||||||
|
this.deleteLibraryFile()
|
||||||
|
} else if (action === 'download') {
|
||||||
|
this.downloadLibraryFile()
|
||||||
|
} else if (action === 'more') {
|
||||||
|
this.$emit('showMore', this.track.audioFile)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteLibraryFile() {
|
||||||
|
const payload = {
|
||||||
|
message: 'This will delete the file from your file system. Are you sure?',
|
||||||
|
callback: (confirmed) => {
|
||||||
|
if (confirmed) {
|
||||||
|
this.$axios
|
||||||
|
.$delete(`/api/items/${this.libraryItemId}/file/${this.track.audioFile.ino}`)
|
||||||
|
.then(() => {
|
||||||
|
this.$toast.success('File deleted')
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to delete file', error)
|
||||||
|
this.$toast.error('Failed to delete file')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 'yesNo'
|
||||||
|
}
|
||||||
|
this.$store.commit('globals/setConfirmPrompt', payload)
|
||||||
|
},
|
||||||
|
downloadLibraryFile() {
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.style.display = 'none'
|
||||||
|
a.href = this.downloadUrl
|
||||||
|
a.download = this.track.metadata.filename
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
setTimeout(() => {
|
||||||
|
a.remove()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -18,35 +18,42 @@
|
|||||||
<th class="text-left px-4">{{ $strings.LabelPath }}</th>
|
<th class="text-left px-4">{{ $strings.LabelPath }}</th>
|
||||||
<th class="text-left w-24 min-w-24">{{ $strings.LabelSize }}</th>
|
<th class="text-left w-24 min-w-24">{{ $strings.LabelSize }}</th>
|
||||||
<th class="text-left px-4 w-24">{{ $strings.LabelType }}</th>
|
<th class="text-left px-4 w-24">{{ $strings.LabelType }}</th>
|
||||||
<th v-if="userCanDelete || userCanDownload" class="text-center w-16"></th>
|
<th v-if="userCanDelete || userCanDownload || (userIsAdmin && audioFiles.length && !inModal)" class="text-center w-16"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-for="file in files">
|
<template v-for="file in filesWithAudioFile">
|
||||||
<tables-library-files-table-row :key="file.path" :libraryItemId="libraryItemId" :showFullPath="showFullPath" :file="file" />
|
<tables-library-files-table-row :key="file.path" :libraryItemId="libraryItemId" :showFullPath="showFullPath" :file="file" :inModal="inModal" @showMore="showMore" />
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
|
<modals-audio-file-data-modal v-model="showAudioFileDataModal" :audio-file="selectedAudioFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
files: {
|
libraryItem: {
|
||||||
type: Array,
|
type: Object,
|
||||||
default: () => []
|
default: () => {}
|
||||||
},
|
},
|
||||||
libraryItemId: String,
|
|
||||||
isMissing: Boolean,
|
isMissing: Boolean,
|
||||||
expanded: Boolean // start expanded
|
expanded: Boolean, // start expanded
|
||||||
|
inModal: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showFiles: false,
|
showFiles: false,
|
||||||
showFullPath: false
|
showFullPath: false,
|
||||||
|
showAudioFileDataModal: false,
|
||||||
|
selectedAudioFile: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
libraryItemId() {
|
||||||
|
return this.libraryItem.id
|
||||||
|
},
|
||||||
userToken() {
|
userToken() {
|
||||||
return this.$store.getters['user/getToken']
|
return this.$store.getters['user/getToken']
|
||||||
},
|
},
|
||||||
@ -58,11 +65,29 @@ export default {
|
|||||||
},
|
},
|
||||||
userIsAdmin() {
|
userIsAdmin() {
|
||||||
return this.$store.getters['user/getIsAdminOrUp']
|
return this.$store.getters['user/getIsAdminOrUp']
|
||||||
|
},
|
||||||
|
files() {
|
||||||
|
return this.libraryItem.libraryFiles || []
|
||||||
|
},
|
||||||
|
audioFiles() {
|
||||||
|
return this.libraryItem.media?.audioFiles || []
|
||||||
|
},
|
||||||
|
filesWithAudioFile() {
|
||||||
|
return this.files.map((file) => {
|
||||||
|
if (file.fileType === 'audio') {
|
||||||
|
file.audioFile = this.audioFiles.find((af) => af.ino === file.ino)
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clickBar() {
|
clickBar() {
|
||||||
this.showFiles = !this.showFiles
|
this.showFiles = !this.showFiles
|
||||||
|
},
|
||||||
|
showMore(audioFile) {
|
||||||
|
this.selectedAudioFile = audioFile
|
||||||
|
this.showAudioFileDataModal = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<td class="px-4">
|
<td class="px-4">
|
||||||
{{ showFullPath ? file.metadata.path : file.metadata.relPath }}
|
{{ showFullPath ? file.metadata.path : file.metadata.relPath }}
|
||||||
</td>
|
</td>
|
||||||
<td class="font-mono">
|
<td>
|
||||||
{{ $bytesPretty(file.metadata.size) }}
|
{{ $bytesPretty(file.metadata.size) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-xs">
|
<td class="text-xs">
|
||||||
@ -25,7 +25,8 @@ export default {
|
|||||||
file: {
|
file: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
}
|
},
|
||||||
|
inModal: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {}
|
||||||
@ -40,6 +41,9 @@ export default {
|
|||||||
userCanDelete() {
|
userCanDelete() {
|
||||||
return this.$store.getters['user/getUserCanDelete']
|
return this.$store.getters['user/getUserCanDelete']
|
||||||
},
|
},
|
||||||
|
userIsAdmin() {
|
||||||
|
return this.$store.getters['user/getIsAdminOrUp']
|
||||||
|
},
|
||||||
downloadUrl() {
|
downloadUrl() {
|
||||||
return `${process.env.serverUrl}/s/item/${this.libraryItemId}/${this.$encodeUriPath(this.file.metadata.relPath).replace(/^\//, '')}?token=${this.userToken}`
|
return `${process.env.serverUrl}/s/item/${this.libraryItemId}/${this.$encodeUriPath(this.file.metadata.relPath).replace(/^\//, '')}?token=${this.userToken}`
|
||||||
},
|
},
|
||||||
@ -57,6 +61,13 @@ export default {
|
|||||||
action: 'delete'
|
action: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// Currently not showing this option in the Files tab modal
|
||||||
|
if (this.userIsAdmin && this.file.audioFile && !this.inModal) {
|
||||||
|
items.push({
|
||||||
|
text: this.$strings.LabelMoreInfo,
|
||||||
|
action: 'more'
|
||||||
|
})
|
||||||
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -66,6 +77,8 @@ export default {
|
|||||||
this.deleteLibraryFile()
|
this.deleteLibraryFile()
|
||||||
} else if (action === 'download') {
|
} else if (action === 'download') {
|
||||||
this.downloadLibraryFile()
|
this.downloadLibraryFile()
|
||||||
|
} else if (action === 'more') {
|
||||||
|
this.$emit('showMore', this.file.audioFile)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteLibraryFile() {
|
deleteLibraryFile() {
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
<div class="h-5 md:h-7 w-5 md:w-7 rounded-full bg-white bg-opacity-10 flex items-center justify-center">
|
<div class="h-5 md:h-7 w-5 md:w-7 rounded-full bg-white bg-opacity-10 flex items-center justify-center">
|
||||||
<span class="text-sm font-mono">{{ tracks.length }}</span>
|
<span class="text-sm font-mono">{{ tracks.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <span class="bg-black-400 rounded-xl py-1 px-2 text-sm font-mono">{{ tracks.length }}</span> -->
|
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
|
<ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
|
||||||
<nuxt-link v-if="userCanUpdate && !isFile" :to="`/audiobook/${libraryItemId}/edit`" class="mr-2 md:mr-4" @mousedown.prevent>
|
<nuxt-link v-if="userCanUpdate && !isFile" :to="`/audiobook/${libraryItemId}/edit`" class="mr-2 md:mr-4" @mousedown.prevent>
|
||||||
@ -21,41 +20,20 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="w-10">#</th>
|
<th class="w-10">#</th>
|
||||||
<th class="text-left">{{ $strings.LabelFilename }}</th>
|
<th class="text-left">{{ $strings.LabelFilename }}</th>
|
||||||
<th class="text-left w-20">{{ $strings.LabelSize }}</th>
|
<th v-if="!showFullPath" class="text-left w-20 hidden lg:table-cell">{{ $strings.LabelCodec }}</th>
|
||||||
<th class="text-left w-20">{{ $strings.LabelDuration }}</th>
|
<th v-if="!showFullPath" class="text-left w-20 hidden xl:table-cell">{{ $strings.LabelBitrate }}</th>
|
||||||
<th v-if="userCanDownload" class="text-center w-20">{{ $strings.LabelDownload }}</th>
|
<th class="text-left w-20 hidden md:table-cell">{{ $strings.LabelSize }}</th>
|
||||||
<th v-if="showExperimentalFeatures" class="text-center w-20">
|
<th class="text-left w-20 hidden sm:table-cell">{{ $strings.LabelDuration }}</th>
|
||||||
<div class="flex items-center">
|
<th class="text-center w-16"></th>
|
||||||
<p>Tone</p>
|
|
||||||
<ui-tooltip text="Experimental feature for testing Tone library metadata scan results. Results logged in browser console." class="ml-2 w-2" direction="left">
|
|
||||||
<span class="material-icons-outlined text-sm">information</span>
|
|
||||||
</ui-tooltip>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<template v-for="track in tracks">
|
<template v-for="track in tracks">
|
||||||
<tr :key="track.index">
|
<tables-audio-tracks-table-row :key="track.index" :track="track" :library-item-id="libraryItemId" :showFullPath="showFullPath" @showMore="showMore" />
|
||||||
<td class="text-center">
|
|
||||||
<p>{{ track.index }}</p>
|
|
||||||
</td>
|
|
||||||
<td class="font-sans">{{ showFullPath ? track.metadata.path : track.metadata.filename }}</td>
|
|
||||||
<td class="font-mono">
|
|
||||||
{{ $bytesPretty(track.metadata.size) }}
|
|
||||||
</td>
|
|
||||||
<td class="font-mono">
|
|
||||||
{{ $secondsToTimestamp(track.duration) }}
|
|
||||||
</td>
|
|
||||||
<td v-if="userCanDownload" class="text-center">
|
|
||||||
<a :href="`${$config.routerBasePath}/s/item/${libraryItemId}/${$encodeUriPath(track.metadata.relPath).replace(/^\//, '')}?token=${userToken}`" download><span class="material-icons icon-text pt-1">download</span></a>
|
|
||||||
</td>
|
|
||||||
<td v-if="showExperimentalFeatures" class="text-center">
|
|
||||||
<ui-icon-btn borderless :loading="toneProbing" icon="search" @click="toneProbe(track.index)" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
|
<modals-audio-file-data-modal v-model="showAudioFileDataModal" :audio-file="selectedAudioFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -77,50 +55,31 @@ export default {
|
|||||||
return {
|
return {
|
||||||
showTracks: false,
|
showTracks: false,
|
||||||
showFullPath: false,
|
showFullPath: false,
|
||||||
toneProbing: false
|
selectedAudioFile: null,
|
||||||
|
showAudioFileDataModal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
userCanDownload() {
|
userCanDownload() {
|
||||||
return this.$store.getters['user/getUserCanDownload']
|
return this.$store.getters['user/getUserCanDownload']
|
||||||
},
|
},
|
||||||
userCanUpdate() {
|
userCanUpdate() {
|
||||||
return this.$store.getters['user/getUserCanUpdate']
|
return this.$store.getters['user/getUserCanUpdate']
|
||||||
},
|
},
|
||||||
|
userCanDelete() {
|
||||||
|
return this.$store.getters['user/getUserCanDelete']
|
||||||
|
},
|
||||||
userIsAdmin() {
|
userIsAdmin() {
|
||||||
return this.$store.getters['user/getIsAdminOrUp']
|
return this.$store.getters['user/getIsAdminOrUp']
|
||||||
},
|
|
||||||
showExperimentalFeatures() {
|
|
||||||
return this.$store.state.showExperimentalFeatures
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clickBar() {
|
clickBar() {
|
||||||
this.showTracks = !this.showTracks
|
this.showTracks = !this.showTracks
|
||||||
},
|
},
|
||||||
toneProbe(index) {
|
showMore(audioFile) {
|
||||||
this.toneProbing = true
|
this.selectedAudioFile = audioFile
|
||||||
|
this.showAudioFileDataModal = true
|
||||||
this.$axios
|
|
||||||
.$post(`/api/items/${this.libraryItemId}/tone-scan/${index}`)
|
|
||||||
.then((data) => {
|
|
||||||
console.log('Tone probe data', data)
|
|
||||||
if (data.error) {
|
|
||||||
this.$toast.error('Tone probe error: ' + data.error)
|
|
||||||
} else {
|
|
||||||
this.$toast.success('Tone probe successful! Check browser console')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Failed to tone probe', error)
|
|
||||||
this.$toast.error('Tone probe failed')
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.toneProbing = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {}
|
mounted() {}
|
||||||
|
70
client/components/widgets/AbridgedIndicator.vue
Normal file
70
client/components/widgets/AbridgedIndicator.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<ui-tooltip :text="$strings.LabelAbridged" direction="top">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="12px" height="12px" viewBox="0 0 512 512" class="ml-1">
|
||||||
|
<path
|
||||||
|
fill="white"
|
||||||
|
d="M 89.00,40.12
|
||||||
|
C 89.00,40.12 127.00,40.12 127.00,40.12
|
||||||
|
127.00,40.12 198.00,40.12 198.00,40.12
|
||||||
|
198.00,40.12 416.00,40.12 416.00,40.12
|
||||||
|
446.58,40.05 472.95,66.42 473.00,97.00
|
||||||
|
473.00,97.00 473.00,303.00 473.00,303.00
|
||||||
|
473.00,303.00 473.00,418.00 473.00,418.00
|
||||||
|
472.65,447.55 445.06,472.95 416.00,473.00
|
||||||
|
416.00,473.00 210.00,473.00 210.00,473.00
|
||||||
|
210.00,473.00 95.00,473.00 95.00,473.00
|
||||||
|
65.45,472.65 40.05,445.06 40.00,416.00
|
||||||
|
40.00,416.00 40.00,136.00 40.00,136.00
|
||||||
|
40.00,136.00 40.00,109.00 40.00,109.00
|
||||||
|
40.00,109.00 40.00,96.00 40.00,96.00
|
||||||
|
40.07,81.58 46.89,67.14 57.01,57.01
|
||||||
|
61.17,52.86 64.86,50.13 70.00,47.31
|
||||||
|
77.25,43.33 81.02,42.18 89.00,40.12 Z
|
||||||
|
M 372.00,392.00
|
||||||
|
C 372.00,392.00 364.02,364.00 364.02,364.00
|
||||||
|
364.02,364.00 350.72,319.00 350.72,319.00
|
||||||
|
350.72,319.00 310.42,183.00 310.42,183.00
|
||||||
|
310.42,183.00 296.86,137.00 296.86,137.00
|
||||||
|
296.86,137.00 291.30,121.99 291.30,121.99
|
||||||
|
291.30,121.99 284.00,121.00 284.00,121.00
|
||||||
|
284.00,121.00 230.00,121.00 230.00,121.00
|
||||||
|
230.00,121.00 222.51,122.02 222.51,122.02
|
||||||
|
222.51,122.02 216.86,137.00 216.86,137.00
|
||||||
|
216.86,137.00 203.28,183.00 203.28,183.00
|
||||||
|
203.28,183.00 163.28,318.00 163.28,318.00
|
||||||
|
163.28,318.00 148.71,367.00 148.71,367.00
|
||||||
|
148.71,367.00 142.00,392.00 142.00,392.00
|
||||||
|
142.00,392.00 183.00,392.00 183.00,392.00
|
||||||
|
183.00,392.00 190.86,390.43 190.86,390.43
|
||||||
|
190.86,390.43 195.86,375.00 195.86,375.00
|
||||||
|
195.86,375.00 206.00,338.00 206.00,338.00
|
||||||
|
206.00,338.00 293.00,338.00 293.00,338.00
|
||||||
|
295.64,338.01 299.26,337.65 301.30,339.60
|
||||||
|
303.23,341.43 304.80,348.22 305.58,351.00
|
||||||
|
305.58,351.00 313.00,378.00 313.00,378.00
|
||||||
|
316.91,391.63 315.20,391.98 325.00,392.00
|
||||||
|
325.00,392.00 372.00,392.00 372.00,392.00 Z
|
||||||
|
M 254.00,170.00
|
||||||
|
C 254.00,170.00 256.00,170.00 256.00,170.00
|
||||||
|
256.00,170.00 263.12,197.00 263.12,197.00
|
||||||
|
263.12,197.00 282.88,268.00 282.88,268.00
|
||||||
|
282.88,268.00 290.00,296.00 290.00,296.00
|
||||||
|
290.00,296.00 219.00,296.00 219.00,296.00
|
||||||
|
219.00,296.00 230.58,253.00 230.58,253.00
|
||||||
|
230.58,253.00 254.00,170.00 254.00,170.00 Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</ui-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tables-tracks-table :title="$strings.LabelStatsAudioTracks" :tracks="media.tracks" :is-file="isFile" :library-item-id="libraryItemId" class="mt-6" />
|
<tables-tracks-table :title="$strings.LabelStatsAudioTracks" :tracks="tracksWithAudioFile" :is-file="isFile" :library-item-id="libraryItemId" class="mt-6" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -34,6 +34,12 @@ export default {
|
|||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
tracksWithAudioFile() {
|
||||||
|
return this.media.tracks.map((track) => {
|
||||||
|
track.audioFile = this.media.audioFiles.find((af) => af.metadata.path === track.metadata.path)
|
||||||
|
return track
|
||||||
|
})
|
||||||
|
},
|
||||||
missingPartChunks() {
|
missingPartChunks() {
|
||||||
if (this.missingParts === 1) return this.missingParts[0]
|
if (this.missingParts === 1) return this.missingParts[0]
|
||||||
var chunks = []
|
var chunks = []
|
||||||
|
@ -1,6 +1,40 @@
|
|||||||
<template>
|
<template>
|
||||||
<ui-tooltip v-if="explicit" :text="$strings.LabelExplicit" direction="top">
|
<ui-tooltip v-if="explicit" :text="$strings.LabelExplicit" direction="top">
|
||||||
<span class="material-icons ml-1" style="font-size: 0.8rem">explicit</span>
|
<svg xmlns="http://www.w3.org/2000/svg" width="12px" height="12px" viewBox="0 0 512 512" class="ml-1">
|
||||||
|
<path
|
||||||
|
fill="white"
|
||||||
|
d="M 89.00,40.12
|
||||||
|
C 89.00,40.12 127.00,40.12 127.00,40.12
|
||||||
|
127.00,40.12 198.00,40.12 198.00,40.12
|
||||||
|
198.00,40.12 416.00,40.12 416.00,40.12
|
||||||
|
446.58,40.05 472.95,66.42 473.00,97.00
|
||||||
|
473.00,97.00 473.00,303.00 473.00,303.00
|
||||||
|
473.00,303.00 473.00,418.00 473.00,418.00
|
||||||
|
472.65,447.55 445.06,472.95 416.00,473.00
|
||||||
|
416.00,473.00 210.00,473.00 210.00,473.00
|
||||||
|
210.00,473.00 95.00,473.00 95.00,473.00
|
||||||
|
65.45,472.65 40.05,445.06 40.00,416.00
|
||||||
|
40.00,416.00 40.00,136.00 40.00,136.00
|
||||||
|
40.00,136.00 40.00,109.00 40.00,109.00
|
||||||
|
40.00,109.00 40.00,96.00 40.00,96.00
|
||||||
|
40.07,81.58 46.89,67.14 57.01,57.01
|
||||||
|
61.17,52.86 64.86,50.13 70.00,47.31
|
||||||
|
77.25,43.33 81.02,42.18 89.00,40.12 Z
|
||||||
|
M 337.00,121.00
|
||||||
|
C 337.00,121.00 175.00,121.00 175.00,121.00
|
||||||
|
175.00,121.00 175.00,392.00 175.00,392.00
|
||||||
|
175.00,392.00 337.00,392.00 337.00,392.00
|
||||||
|
337.00,392.00 337.00,349.00 337.00,349.00
|
||||||
|
337.00,349.00 226.00,349.00 226.00,349.00
|
||||||
|
226.00,349.00 226.00,274.00 226.00,274.00
|
||||||
|
226.00,274.00 332.00,274.00 332.00,274.00
|
||||||
|
332.00,274.00 332.00,232.00 332.00,232.00
|
||||||
|
332.00,232.00 226.00,232.00 226.00,232.00
|
||||||
|
226.00,232.00 226.00,164.00 226.00,164.00
|
||||||
|
226.00,164.00 337.00,164.00 337.00,164.00
|
||||||
|
337.00,164.00 337.00,121.00 337.00,121.00 Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="page-wrapper" class="bg-bg page overflow-hidden" :class="streamLibraryItem ? 'streaming' : ''">
|
<div id="page-wrapper" class="bg-bg page overflow-hidden" :class="streamLibraryItem ? 'streaming' : ''">
|
||||||
<div class="w-full h-full overflow-y-auto px-2 py-6 md:p-8">
|
<div class="w-full h-full overflow-y-auto px-2 py-6 lg:p-8">
|
||||||
<div class="flex flex-col md:flex-row max-w-6xl mx-auto">
|
<div class="flex flex-col lg:flex-row max-w-6xl mx-auto">
|
||||||
<div class="w-full flex justify-center md:block md:w-52" style="min-width: 208px">
|
<div class="w-full flex justify-center lg:block lg:w-52" style="min-width: 208px">
|
||||||
<div class="relative" style="height: fit-content">
|
<div class="relative" style="height: fit-content">
|
||||||
<covers-book-cover :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
<covers-book-cover :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||||
|
|
||||||
@ -21,13 +21,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-2 py-6 md:py-0 md:px-10">
|
<div class="flex-grow px-2 py-6 lg:py-0 md:px-10">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h1 class="text-2xl md:text-3xl font-semibold">
|
<h1 class="text-2xl md:text-3xl font-semibold">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
<widgets-explicit-indicator :explicit="isExplicit" />
|
<widgets-explicit-indicator :explicit="isExplicit" />
|
||||||
|
<widgets-abridged-indicator v-if="isAbridged" />
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -124,14 +125,6 @@
|
|||||||
{{ sizePretty }}
|
{{ sizePretty }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isBook" class="flex py-0.5">
|
|
||||||
<div class="w-32">
|
|
||||||
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelAbridged }}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{ isAbridged ? 'Yes' : 'No' }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hidden md:block flex-grow" />
|
<div class="hidden md:block flex-grow" />
|
||||||
</div>
|
</div>
|
||||||
@ -209,7 +202,7 @@
|
|||||||
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" menu-width="148px" @action="contextMenuAction">
|
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" menu-width="148px" @action="contextMenuAction">
|
||||||
<template #default="{ showMenu, clickShowMenu, disabled }">
|
<template #default="{ showMenu, clickShowMenu, disabled }">
|
||||||
<button type="button" :disabled="disabled" class="mx-0.5 icon-btn bg-primary border border-gray-600 w-9 h-9 rounded-md flex items-center justify-center relative" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
<button type="button" :disabled="disabled" class="mx-0.5 icon-btn bg-primary border border-gray-600 w-9 h-9 rounded-md flex items-center justify-center relative" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
||||||
<span class="material-icons">more_vert</span>
|
<span class="material-icons">more_horiz</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</ui-context-menu-dropdown>
|
</ui-context-menu-dropdown>
|
||||||
@ -231,7 +224,7 @@
|
|||||||
|
|
||||||
<tables-chapters-table v-if="chapters.length" :library-item="libraryItem" class="mt-6" />
|
<tables-chapters-table v-if="chapters.length" :library-item="libraryItem" class="mt-6" />
|
||||||
|
|
||||||
<tables-library-files-table v-if="libraryFiles.length" :is-missing="isMissing" :library-item-id="libraryItemId" :files="libraryFiles" class="mt-6" />
|
<tables-library-files-table v-if="libraryFiles.length" :is-missing="isMissing" :library-item="libraryItem" class="mt-6" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -562,12 +555,12 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.userCanDelete) {
|
if (this.userCanDelete) {
|
||||||
// items.push({
|
items.push({
|
||||||
// text: this.$strings.ButtonDelete,
|
text: this.$strings.ButtonDelete,
|
||||||
// action: 'delete'
|
action: 'delete'
|
||||||
// })
|
})
|
||||||
// }
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
@ -818,14 +811,18 @@ export default {
|
|||||||
},
|
},
|
||||||
deleteLibraryItem() {
|
deleteLibraryItem() {
|
||||||
const payload = {
|
const payload = {
|
||||||
message: 'This will delete the library item files from your file system. Are you sure?',
|
message: 'This will delete the library item from the database and your file system. Are you sure?',
|
||||||
callback: (confirmed) => {
|
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.',
|
||||||
|
yesButtonText: this.$strings.ButtonDelete,
|
||||||
|
yesButtonColor: 'error',
|
||||||
|
checkboxDefaultValue: true,
|
||||||
|
callback: (confirmed, hardDelete) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$axios
|
this.$axios
|
||||||
.$delete(`/api/items/${this.libraryItemId}?hard=1`)
|
.$delete(`/api/items/${this.libraryItemId}?hard=${hardDelete ? 1 : 0}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$toast.success('Item deleted')
|
this.$toast.success('Item deleted')
|
||||||
this.$router.replace(`/library/${this.libraryId}/bookshelf`)
|
this.$router.replace(`/library/${this.libraryId}`)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to delete item', error)
|
console.error('Failed to delete item', error)
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "Zum Schutz vor Fehlkonfigurationen schlagen Sicherungen fehl, wenn sie die konfigurierte Größe überschreiten.",
|
"LabelBackupsMaxBackupSizeHelp": "Zum Schutz vor Fehlkonfigurationen schlagen Sicherungen fehl, wenn sie die konfigurierte Größe überschreiten.",
|
||||||
"LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen",
|
"LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen",
|
||||||
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn Sie bereits mehrere Sicherungen als die definierte max. Anzahl haben, sollten Sie diese manuell entfernen.",
|
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn Sie bereits mehrere Sicherungen als die definierte max. Anzahl haben, sollten Sie diese manuell entfernen.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Bücher",
|
"LabelBooks": "Bücher",
|
||||||
"LabelChangePassword": "Passwort ändern",
|
"LabelChangePassword": "Passwort ändern",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "gefundene Kapitel",
|
"LabelChaptersFound": "gefundene Kapitel",
|
||||||
"LabelChapterTitle": "Kapitelüberschrift",
|
"LabelChapterTitle": "Kapitelüberschrift",
|
||||||
"LabelClosePlayer": "Player schließen",
|
"LabelClosePlayer": "Player schließen",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Serien zusammenfassen",
|
"LabelCollapseSeries": "Serien zusammenfassen",
|
||||||
"LabelCollections": "Sammlungen",
|
"LabelCollections": "Sammlungen",
|
||||||
"LabelComplete": "Vollständig",
|
"LabelComplete": "Vollständig",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Laufzeit",
|
"LabelDuration": "Laufzeit",
|
||||||
"LabelDurationFound": "Gefundene Laufzeit:",
|
"LabelDurationFound": "Gefundene Laufzeit:",
|
||||||
"LabelEdit": "Bearbeiten",
|
"LabelEdit": "Bearbeiten",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Aktivieren",
|
"LabelEnable": "Aktivieren",
|
||||||
"LabelEnd": "Ende",
|
"LabelEnd": "Ende",
|
||||||
"LabelEpisode": "Episode",
|
"LabelEpisode": "Episode",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "beendet",
|
"LabelFinished": "beendet",
|
||||||
"LabelFolder": "Ordner",
|
"LabelFolder": "Ordner",
|
||||||
"LabelFolders": "Verzeichnisse",
|
"LabelFolders": "Verzeichnisse",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Kategorie",
|
"LabelGenre": "Kategorie",
|
||||||
"LabelGenres": "Kategorien",
|
"LabelGenres": "Kategorien",
|
||||||
"LabelHardDeleteFile": "Datei dauerhaft löschen",
|
"LabelHardDeleteFile": "Datei dauerhaft löschen",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Medientyp",
|
"LabelMediaType": "Medientyp",
|
||||||
"LabelMetadataProvider": "Metadatenanbieter",
|
"LabelMetadataProvider": "Metadatenanbieter",
|
||||||
"LabelMetaTag": "Meta Schlagwort",
|
"LabelMetaTag": "Meta Schlagwort",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minute",
|
"LabelMinute": "Minute",
|
||||||
"LabelMissing": "Fehlend",
|
"LabelMissing": "Fehlend",
|
||||||
"LabelMissingParts": "Fehlende Teile",
|
"LabelMissingParts": "Fehlende Teile",
|
||||||
"LabelMore": "Mehr",
|
"LabelMore": "Mehr",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNarrator": "Erzähler",
|
"LabelNarrator": "Erzähler",
|
||||||
"LabelNarrators": "Erzähler",
|
"LabelNarrators": "Erzähler",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Schlagwörter",
|
"LabelTags": "Schlagwörter",
|
||||||
"LabelTagsAccessibleToUser": "Für Benutzer zugängliche Schlagwörter",
|
"LabelTagsAccessibleToUser": "Für Benutzer zugängliche Schlagwörter",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Gehörte Zeit",
|
"LabelTimeListened": "Gehörte Zeit",
|
||||||
"LabelTimeListenedToday": "Heute gehörte Zeit",
|
"LabelTimeListenedToday": "Heute gehörte Zeit",
|
||||||
"LabelTimeRemaining": "{0} verbleibend",
|
"LabelTimeRemaining": "{0} verbleibend",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
||||||
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
||||||
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Books",
|
"LabelBooks": "Books",
|
||||||
"LabelChangePassword": "Change Password",
|
"LabelChangePassword": "Change Password",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "chapters found",
|
"LabelChaptersFound": "chapters found",
|
||||||
"LabelChapterTitle": "Chapter Title",
|
"LabelChapterTitle": "Chapter Title",
|
||||||
"LabelClosePlayer": "Close player",
|
"LabelClosePlayer": "Close player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Collapse Series",
|
"LabelCollapseSeries": "Collapse Series",
|
||||||
"LabelCollections": "Collections",
|
"LabelCollections": "Collections",
|
||||||
"LabelComplete": "Complete",
|
"LabelComplete": "Complete",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
"LabelDurationFound": "Duration found:",
|
"LabelDurationFound": "Duration found:",
|
||||||
"LabelEdit": "Edit",
|
"LabelEdit": "Edit",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Enable",
|
"LabelEnable": "Enable",
|
||||||
"LabelEnd": "End",
|
"LabelEnd": "End",
|
||||||
"LabelEpisode": "Episode",
|
"LabelEpisode": "Episode",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Finished",
|
"LabelFinished": "Finished",
|
||||||
"LabelFolder": "Folder",
|
"LabelFolder": "Folder",
|
||||||
"LabelFolders": "Folders",
|
"LabelFolders": "Folders",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Hard delete file",
|
"LabelHardDeleteFile": "Hard delete file",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Media Type",
|
"LabelMediaType": "Media Type",
|
||||||
"LabelMetadataProvider": "Metadata Provider",
|
"LabelMetadataProvider": "Metadata Provider",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minute",
|
"LabelMinute": "Minute",
|
||||||
"LabelMissing": "Missing",
|
"LabelMissing": "Missing",
|
||||||
"LabelMissingParts": "Missing Parts",
|
"LabelMissingParts": "Missing Parts",
|
||||||
"LabelMore": "More",
|
"LabelMore": "More",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Narrators",
|
"LabelNarrators": "Narrators",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Time Listened",
|
"LabelTimeListened": "Time Listened",
|
||||||
"LabelTimeListenedToday": "Time Listened Today",
|
"LabelTimeListenedToday": "Time Listened Today",
|
||||||
"LabelTimeRemaining": "{0} remaining",
|
"LabelTimeRemaining": "{0} remaining",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "Como protección contra una configuración errónea, los respaldos fallaran si se excede el tamaño configurado.",
|
"LabelBackupsMaxBackupSizeHelp": "Como protección contra una configuración errónea, los respaldos fallaran si se excede el tamaño configurado.",
|
||||||
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
|
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
|
||||||
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, necesita removerlos manualmente.",
|
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, necesita removerlos manualmente.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Libros",
|
"LabelBooks": "Libros",
|
||||||
"LabelChangePassword": "Cambiar Contraseña",
|
"LabelChangePassword": "Cambiar Contraseña",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "Capitulo Encontrado",
|
"LabelChaptersFound": "Capitulo Encontrado",
|
||||||
"LabelChapterTitle": "Titulo del Capitulo",
|
"LabelChapterTitle": "Titulo del Capitulo",
|
||||||
"LabelClosePlayer": "Close player",
|
"LabelClosePlayer": "Close player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Colapsar Series",
|
"LabelCollapseSeries": "Colapsar Series",
|
||||||
"LabelCollections": "Colecciones",
|
"LabelCollections": "Colecciones",
|
||||||
"LabelComplete": "Completo",
|
"LabelComplete": "Completo",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Duración",
|
"LabelDuration": "Duración",
|
||||||
"LabelDurationFound": "Duración Comprobada:",
|
"LabelDurationFound": "Duración Comprobada:",
|
||||||
"LabelEdit": "Editar",
|
"LabelEdit": "Editar",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Habilitar",
|
"LabelEnable": "Habilitar",
|
||||||
"LabelEnd": "Fin",
|
"LabelEnd": "Fin",
|
||||||
"LabelEpisode": "Episodio",
|
"LabelEpisode": "Episodio",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Terminado",
|
"LabelFinished": "Terminado",
|
||||||
"LabelFolder": "Carpeta",
|
"LabelFolder": "Carpeta",
|
||||||
"LabelFolders": "Carpetas",
|
"LabelFolders": "Carpetas",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genero",
|
"LabelGenre": "Genero",
|
||||||
"LabelGenres": "Géneros",
|
"LabelGenres": "Géneros",
|
||||||
"LabelHardDeleteFile": "Eliminar Definitivamente",
|
"LabelHardDeleteFile": "Eliminar Definitivamente",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Tipo de Multimedia",
|
"LabelMediaType": "Tipo de Multimedia",
|
||||||
"LabelMetadataProvider": "Proveedor de Metadata",
|
"LabelMetadataProvider": "Proveedor de Metadata",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minuto",
|
"LabelMinute": "Minuto",
|
||||||
"LabelMissing": "Ausente",
|
"LabelMissing": "Ausente",
|
||||||
"LabelMissingParts": "Partes Ausentes",
|
"LabelMissingParts": "Partes Ausentes",
|
||||||
"LabelMore": "Mas",
|
"LabelMore": "Mas",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Nombre",
|
"LabelName": "Nombre",
|
||||||
"LabelNarrator": "Narrador",
|
"LabelNarrator": "Narrador",
|
||||||
"LabelNarrators": "Narradores",
|
"LabelNarrators": "Narradores",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Etiquetas",
|
"LabelTags": "Etiquetas",
|
||||||
"LabelTagsAccessibleToUser": "Etiquetas Accessible para el Usuario",
|
"LabelTagsAccessibleToUser": "Etiquetas Accessible para el Usuario",
|
||||||
"LabelTasks": "Tareas Corriendo",
|
"LabelTasks": "Tareas Corriendo",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Tiempo Escuchando",
|
"LabelTimeListened": "Tiempo Escuchando",
|
||||||
"LabelTimeListenedToday": "Tiempo Escuchando Hoy",
|
"LabelTimeListenedToday": "Tiempo Escuchando Hoy",
|
||||||
"LabelTimeRemaining": "{0} restante",
|
"LabelTimeRemaining": "{0} restante",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "Afin de prévenir les mauvaises configuration, la sauvegarde échouera si elle excède la taille limite.",
|
"LabelBackupsMaxBackupSizeHelp": "Afin de prévenir les mauvaises configuration, la sauvegarde échouera si elle excède la taille limite.",
|
||||||
"LabelBackupsNumberToKeep": "Nombre de sauvegardes à maintenir",
|
"LabelBackupsNumberToKeep": "Nombre de sauvegardes à maintenir",
|
||||||
"LabelBackupsNumberToKeepHelp": "Une seule sauvegarde sera effacée à la fois. Si vous avez plus de sauvegardes à effacer, vous devrez le faire manuellement.",
|
"LabelBackupsNumberToKeepHelp": "Une seule sauvegarde sera effacée à la fois. Si vous avez plus de sauvegardes à effacer, vous devrez le faire manuellement.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Livres",
|
"LabelBooks": "Livres",
|
||||||
"LabelChangePassword": "Modifier le mot de passe",
|
"LabelChangePassword": "Modifier le mot de passe",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "Chapitres trouvés",
|
"LabelChaptersFound": "Chapitres trouvés",
|
||||||
"LabelChapterTitle": "Titres du chapitre",
|
"LabelChapterTitle": "Titres du chapitre",
|
||||||
"LabelClosePlayer": "Fermer le lecteur",
|
"LabelClosePlayer": "Fermer le lecteur",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Réduire les séries",
|
"LabelCollapseSeries": "Réduire les séries",
|
||||||
"LabelCollections": "Collections",
|
"LabelCollections": "Collections",
|
||||||
"LabelComplete": "Complet",
|
"LabelComplete": "Complet",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Durée",
|
"LabelDuration": "Durée",
|
||||||
"LabelDurationFound": "Durée trouvée :",
|
"LabelDurationFound": "Durée trouvée :",
|
||||||
"LabelEdit": "Modifier",
|
"LabelEdit": "Modifier",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Activer",
|
"LabelEnable": "Activer",
|
||||||
"LabelEnd": "Fin",
|
"LabelEnd": "Fin",
|
||||||
"LabelEpisode": "Épisode",
|
"LabelEpisode": "Épisode",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Fini(e)",
|
"LabelFinished": "Fini(e)",
|
||||||
"LabelFolder": "Dossier",
|
"LabelFolder": "Dossier",
|
||||||
"LabelFolders": "Dossiers",
|
"LabelFolders": "Dossiers",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Suppression du fichier",
|
"LabelHardDeleteFile": "Suppression du fichier",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Type de média",
|
"LabelMediaType": "Type de média",
|
||||||
"LabelMetadataProvider": "Fournisseur de métadonnées",
|
"LabelMetadataProvider": "Fournisseur de métadonnées",
|
||||||
"LabelMetaTag": "Etiquette de métadonnée",
|
"LabelMetaTag": "Etiquette de métadonnée",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minute",
|
"LabelMinute": "Minute",
|
||||||
"LabelMissing": "Manquant",
|
"LabelMissing": "Manquant",
|
||||||
"LabelMissingParts": "Parties manquantes",
|
"LabelMissingParts": "Parties manquantes",
|
||||||
"LabelMore": "Plus",
|
"LabelMore": "Plus",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Nom",
|
"LabelName": "Nom",
|
||||||
"LabelNarrator": "Narrateur",
|
"LabelNarrator": "Narrateur",
|
||||||
"LabelNarrators": "Narrateurs",
|
"LabelNarrators": "Narrateurs",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Étiquettes",
|
"LabelTags": "Étiquettes",
|
||||||
"LabelTagsAccessibleToUser": "Étiquettes accessibles à l’utilisateur",
|
"LabelTagsAccessibleToUser": "Étiquettes accessibles à l’utilisateur",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Temps d’écoute",
|
"LabelTimeListened": "Temps d’écoute",
|
||||||
"LabelTimeListenedToday": "Nombres d’écoutes Aujourd’hui",
|
"LabelTimeListenedToday": "Nombres d’écoutes Aujourd’hui",
|
||||||
"LabelTimeRemaining": "{0} restantes",
|
"LabelTimeRemaining": "{0} restantes",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
||||||
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
||||||
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Books",
|
"LabelBooks": "Books",
|
||||||
"LabelChangePassword": "Change Password",
|
"LabelChangePassword": "Change Password",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "chapters found",
|
"LabelChaptersFound": "chapters found",
|
||||||
"LabelChapterTitle": "Chapter Title",
|
"LabelChapterTitle": "Chapter Title",
|
||||||
"LabelClosePlayer": "Close player",
|
"LabelClosePlayer": "Close player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Collapse Series",
|
"LabelCollapseSeries": "Collapse Series",
|
||||||
"LabelCollections": "Collections",
|
"LabelCollections": "Collections",
|
||||||
"LabelComplete": "Complete",
|
"LabelComplete": "Complete",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
"LabelDurationFound": "Duration found:",
|
"LabelDurationFound": "Duration found:",
|
||||||
"LabelEdit": "Edit",
|
"LabelEdit": "Edit",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Enable",
|
"LabelEnable": "Enable",
|
||||||
"LabelEnd": "End",
|
"LabelEnd": "End",
|
||||||
"LabelEpisode": "Episode",
|
"LabelEpisode": "Episode",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Finished",
|
"LabelFinished": "Finished",
|
||||||
"LabelFolder": "Folder",
|
"LabelFolder": "Folder",
|
||||||
"LabelFolders": "Folders",
|
"LabelFolders": "Folders",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Hard delete file",
|
"LabelHardDeleteFile": "Hard delete file",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Media Type",
|
"LabelMediaType": "Media Type",
|
||||||
"LabelMetadataProvider": "Metadata Provider",
|
"LabelMetadataProvider": "Metadata Provider",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minute",
|
"LabelMinute": "Minute",
|
||||||
"LabelMissing": "Missing",
|
"LabelMissing": "Missing",
|
||||||
"LabelMissingParts": "Missing Parts",
|
"LabelMissingParts": "Missing Parts",
|
||||||
"LabelMore": "More",
|
"LabelMore": "More",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Narrators",
|
"LabelNarrators": "Narrators",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Time Listened",
|
"LabelTimeListened": "Time Listened",
|
||||||
"LabelTimeListenedToday": "Time Listened Today",
|
"LabelTimeListenedToday": "Time Listened Today",
|
||||||
"LabelTimeRemaining": "{0} remaining",
|
"LabelTimeRemaining": "{0} remaining",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
||||||
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
"LabelBackupsNumberToKeep": "Number of backups to keep",
|
||||||
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Books",
|
"LabelBooks": "Books",
|
||||||
"LabelChangePassword": "Change Password",
|
"LabelChangePassword": "Change Password",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "chapters found",
|
"LabelChaptersFound": "chapters found",
|
||||||
"LabelChapterTitle": "Chapter Title",
|
"LabelChapterTitle": "Chapter Title",
|
||||||
"LabelClosePlayer": "Close player",
|
"LabelClosePlayer": "Close player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Collapse Series",
|
"LabelCollapseSeries": "Collapse Series",
|
||||||
"LabelCollections": "Collections",
|
"LabelCollections": "Collections",
|
||||||
"LabelComplete": "Complete",
|
"LabelComplete": "Complete",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
"LabelDurationFound": "Duration found:",
|
"LabelDurationFound": "Duration found:",
|
||||||
"LabelEdit": "Edit",
|
"LabelEdit": "Edit",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Enable",
|
"LabelEnable": "Enable",
|
||||||
"LabelEnd": "End",
|
"LabelEnd": "End",
|
||||||
"LabelEpisode": "Episode",
|
"LabelEpisode": "Episode",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Finished",
|
"LabelFinished": "Finished",
|
||||||
"LabelFolder": "Folder",
|
"LabelFolder": "Folder",
|
||||||
"LabelFolders": "Folders",
|
"LabelFolders": "Folders",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Hard delete file",
|
"LabelHardDeleteFile": "Hard delete file",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Media Type",
|
"LabelMediaType": "Media Type",
|
||||||
"LabelMetadataProvider": "Metadata Provider",
|
"LabelMetadataProvider": "Metadata Provider",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minute",
|
"LabelMinute": "Minute",
|
||||||
"LabelMissing": "Missing",
|
"LabelMissing": "Missing",
|
||||||
"LabelMissingParts": "Missing Parts",
|
"LabelMissingParts": "Missing Parts",
|
||||||
"LabelMore": "More",
|
"LabelMore": "More",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Narrators",
|
"LabelNarrators": "Narrators",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Time Listened",
|
"LabelTimeListened": "Time Listened",
|
||||||
"LabelTimeListenedToday": "Time Listened Today",
|
"LabelTimeListenedToday": "Time Listened Today",
|
||||||
"LabelTimeRemaining": "{0} remaining",
|
"LabelTimeRemaining": "{0} remaining",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
||||||
"LabelBackupsNumberToKeep": "Broj backupa zadržati",
|
"LabelBackupsNumberToKeep": "Broj backupa zadržati",
|
||||||
"LabelBackupsNumberToKeepHelp": "Samo 1 backup će biti odjednom obrisan. Ako koristite više njih, morati ćete ih ručno ukloniti.",
|
"LabelBackupsNumberToKeepHelp": "Samo 1 backup će biti odjednom obrisan. Ako koristite više njih, morati ćete ih ručno ukloniti.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Knjige",
|
"LabelBooks": "Knjige",
|
||||||
"LabelChangePassword": "Promijeni lozinku",
|
"LabelChangePassword": "Promijeni lozinku",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "poglavlja pronađena",
|
"LabelChaptersFound": "poglavlja pronađena",
|
||||||
"LabelChapterTitle": "Ime poglavlja",
|
"LabelChapterTitle": "Ime poglavlja",
|
||||||
"LabelClosePlayer": "Close player",
|
"LabelClosePlayer": "Close player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Collapse Series",
|
"LabelCollapseSeries": "Collapse Series",
|
||||||
"LabelCollections": "Kolekcije",
|
"LabelCollections": "Kolekcije",
|
||||||
"LabelComplete": "Complete",
|
"LabelComplete": "Complete",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Trajanje",
|
"LabelDuration": "Trajanje",
|
||||||
"LabelDurationFound": "Pronađeno trajanje:",
|
"LabelDurationFound": "Pronađeno trajanje:",
|
||||||
"LabelEdit": "Uredi",
|
"LabelEdit": "Uredi",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Uključi",
|
"LabelEnable": "Uključi",
|
||||||
"LabelEnd": "Kraj",
|
"LabelEnd": "Kraj",
|
||||||
"LabelEpisode": "Epizoda",
|
"LabelEpisode": "Epizoda",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Finished",
|
"LabelFinished": "Finished",
|
||||||
"LabelFolder": "Folder",
|
"LabelFolder": "Folder",
|
||||||
"LabelFolders": "Folderi",
|
"LabelFolders": "Folderi",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Žanrovi",
|
"LabelGenres": "Žanrovi",
|
||||||
"LabelHardDeleteFile": "Obriši datoteku zauvijek",
|
"LabelHardDeleteFile": "Obriši datoteku zauvijek",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Media Type",
|
"LabelMediaType": "Media Type",
|
||||||
"LabelMetadataProvider": "Poslužitelj metapodataka ",
|
"LabelMetadataProvider": "Poslužitelj metapodataka ",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minuta",
|
"LabelMinute": "Minuta",
|
||||||
"LabelMissing": "Nedostaje",
|
"LabelMissing": "Nedostaje",
|
||||||
"LabelMissingParts": "Nedostajali dijelovi",
|
"LabelMissingParts": "Nedostajali dijelovi",
|
||||||
"LabelMore": "Više",
|
"LabelMore": "Više",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Ime",
|
"LabelName": "Ime",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Naratori",
|
"LabelNarrators": "Naratori",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTagsAccessibleToUser": "Tags dostupni korisniku",
|
"LabelTagsAccessibleToUser": "Tags dostupni korisniku",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Vremena odslušano",
|
"LabelTimeListened": "Vremena odslušano",
|
||||||
"LabelTimeListenedToday": "Vremena odslušano danas",
|
"LabelTimeListenedToday": "Vremena odslušano danas",
|
||||||
"LabelTimeRemaining": "{0} preostalo",
|
"LabelTimeRemaining": "{0} preostalo",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "Come protezione contro gli errori di config, i backup falliranno se superano la dimensione configurata.",
|
"LabelBackupsMaxBackupSizeHelp": "Come protezione contro gli errori di config, i backup falliranno se superano la dimensione configurata.",
|
||||||
"LabelBackupsNumberToKeep": "Numero di backup da mantenere",
|
"LabelBackupsNumberToKeep": "Numero di backup da mantenere",
|
||||||
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
|
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Libri",
|
"LabelBooks": "Libri",
|
||||||
"LabelChangePassword": "Cambia Password",
|
"LabelChangePassword": "Cambia Password",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "Capitoli Trovati",
|
"LabelChaptersFound": "Capitoli Trovati",
|
||||||
"LabelChapterTitle": "Titoli dei Capitoli",
|
"LabelChapterTitle": "Titoli dei Capitoli",
|
||||||
"LabelClosePlayer": "Chiudi player",
|
"LabelClosePlayer": "Chiudi player",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Comprimi Serie",
|
"LabelCollapseSeries": "Comprimi Serie",
|
||||||
"LabelCollections": "Raccolte",
|
"LabelCollections": "Raccolte",
|
||||||
"LabelComplete": "Completo",
|
"LabelComplete": "Completo",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Durata",
|
"LabelDuration": "Durata",
|
||||||
"LabelDurationFound": "Durata Trovata:",
|
"LabelDurationFound": "Durata Trovata:",
|
||||||
"LabelEdit": "Modifica",
|
"LabelEdit": "Modifica",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Abilita",
|
"LabelEnable": "Abilita",
|
||||||
"LabelEnd": "Fine",
|
"LabelEnd": "Fine",
|
||||||
"LabelEpisode": "Episodio",
|
"LabelEpisode": "Episodio",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Finita",
|
"LabelFinished": "Finita",
|
||||||
"LabelFolder": "Cartella",
|
"LabelFolder": "Cartella",
|
||||||
"LabelFolders": "Cartelle",
|
"LabelFolders": "Cartelle",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Genere",
|
"LabelGenre": "Genere",
|
||||||
"LabelGenres": "Generi",
|
"LabelGenres": "Generi",
|
||||||
"LabelHardDeleteFile": "Elimina Definitivamente",
|
"LabelHardDeleteFile": "Elimina Definitivamente",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Tipo Media",
|
"LabelMediaType": "Tipo Media",
|
||||||
"LabelMetadataProvider": "Metadata Provider",
|
"LabelMetadataProvider": "Metadata Provider",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minuto",
|
"LabelMinute": "Minuto",
|
||||||
"LabelMissing": "Altro",
|
"LabelMissing": "Altro",
|
||||||
"LabelMissingParts": "Parti rimantenti",
|
"LabelMissingParts": "Parti rimantenti",
|
||||||
"LabelMore": "Molto",
|
"LabelMore": "Molto",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Nome",
|
"LabelName": "Nome",
|
||||||
"LabelNarrator": "Narratore",
|
"LabelNarrator": "Narratore",
|
||||||
"LabelNarrators": "Narratori",
|
"LabelNarrators": "Narratori",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tags",
|
"LabelTags": "Tags",
|
||||||
"LabelTagsAccessibleToUser": "Tags permessi agli Utenti",
|
"LabelTagsAccessibleToUser": "Tags permessi agli Utenti",
|
||||||
"LabelTasks": "Processi in esecuzione",
|
"LabelTasks": "Processi in esecuzione",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Tempo di Ascolto",
|
"LabelTimeListened": "Tempo di Ascolto",
|
||||||
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
||||||
"LabelTimeRemaining": "{0} rimanente",
|
"LabelTimeRemaining": "{0} rimanente",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "Jako zabezpieczenie przed błędną konfiguracją, kopie zapasowe nie będą wykonywane, jeśli przekroczą skonfigurowany rozmiar.",
|
"LabelBackupsMaxBackupSizeHelp": "Jako zabezpieczenie przed błędną konfiguracją, kopie zapasowe nie będą wykonywane, jeśli przekroczą skonfigurowany rozmiar.",
|
||||||
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
|
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
|
||||||
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
|
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Książki",
|
"LabelBooks": "Książki",
|
||||||
"LabelChangePassword": "Zmień hasło",
|
"LabelChangePassword": "Zmień hasło",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "Znalezione rozdziały",
|
"LabelChaptersFound": "Znalezione rozdziały",
|
||||||
"LabelChapterTitle": "Tytuł rozdziału",
|
"LabelChapterTitle": "Tytuł rozdziału",
|
||||||
"LabelClosePlayer": "Zamknij odtwarzacz",
|
"LabelClosePlayer": "Zamknij odtwarzacz",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Podsumuj serię",
|
"LabelCollapseSeries": "Podsumuj serię",
|
||||||
"LabelCollections": "Kolekcje",
|
"LabelCollections": "Kolekcje",
|
||||||
"LabelComplete": "Ukończone",
|
"LabelComplete": "Ukończone",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Czas trwania",
|
"LabelDuration": "Czas trwania",
|
||||||
"LabelDurationFound": "Znaleziona długość:",
|
"LabelDurationFound": "Znaleziona długość:",
|
||||||
"LabelEdit": "Edytuj",
|
"LabelEdit": "Edytuj",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Włącz",
|
"LabelEnable": "Włącz",
|
||||||
"LabelEnd": "Zakończ",
|
"LabelEnd": "Zakończ",
|
||||||
"LabelEpisode": "Odcinek",
|
"LabelEpisode": "Odcinek",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Zakończone",
|
"LabelFinished": "Zakończone",
|
||||||
"LabelFolder": "Folder",
|
"LabelFolder": "Folder",
|
||||||
"LabelFolders": "Foldery",
|
"LabelFolders": "Foldery",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Gatunek",
|
"LabelGenre": "Gatunek",
|
||||||
"LabelGenres": "Gatunki",
|
"LabelGenres": "Gatunki",
|
||||||
"LabelHardDeleteFile": "Usuń trwale plik",
|
"LabelHardDeleteFile": "Usuń trwale plik",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Typ mediów",
|
"LabelMediaType": "Typ mediów",
|
||||||
"LabelMetadataProvider": "Dostawca metadanych",
|
"LabelMetadataProvider": "Dostawca metadanych",
|
||||||
"LabelMetaTag": "Tag",
|
"LabelMetaTag": "Tag",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Minuta",
|
"LabelMinute": "Minuta",
|
||||||
"LabelMissing": "Brakujący",
|
"LabelMissing": "Brakujący",
|
||||||
"LabelMissingParts": "Brakujące cześci",
|
"LabelMissingParts": "Brakujące cześci",
|
||||||
"LabelMore": "Więcej",
|
"LabelMore": "Więcej",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Nazwa",
|
"LabelName": "Nazwa",
|
||||||
"LabelNarrator": "Narrator",
|
"LabelNarrator": "Narrator",
|
||||||
"LabelNarrators": "Lektorzy",
|
"LabelNarrators": "Lektorzy",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Tagi",
|
"LabelTags": "Tagi",
|
||||||
"LabelTagsAccessibleToUser": "Tagi dostępne dla użytkownika",
|
"LabelTagsAccessibleToUser": "Tagi dostępne dla użytkownika",
|
||||||
"LabelTasks": "Tasks Running",
|
"LabelTasks": "Tasks Running",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Czas odtwarzania",
|
"LabelTimeListened": "Czas odtwarzania",
|
||||||
"LabelTimeListenedToday": "Czas odtwarzania dzisiaj",
|
"LabelTimeListenedToday": "Czas odtwarzania dzisiaj",
|
||||||
"LabelTimeRemaining": "Pozostało {0}",
|
"LabelTimeRemaining": "Pozostało {0}",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "В качестве защиты процесс бэкапирования будет завершаться ошибкой, если будет превышен настроенный размер.",
|
"LabelBackupsMaxBackupSizeHelp": "В качестве защиты процесс бэкапирования будет завершаться ошибкой, если будет превышен настроенный размер.",
|
||||||
"LabelBackupsNumberToKeep": "Сохранять бэкапов",
|
"LabelBackupsNumberToKeep": "Сохранять бэкапов",
|
||||||
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
|
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Книги",
|
"LabelBooks": "Книги",
|
||||||
"LabelChangePassword": "Изменить пароль",
|
"LabelChangePassword": "Изменить пароль",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "глав найдено",
|
"LabelChaptersFound": "глав найдено",
|
||||||
"LabelChapterTitle": "Название главы",
|
"LabelChapterTitle": "Название главы",
|
||||||
"LabelClosePlayer": "Закрыть проигрыватель",
|
"LabelClosePlayer": "Закрыть проигрыватель",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Свернуть серии",
|
"LabelCollapseSeries": "Свернуть серии",
|
||||||
"LabelCollections": "Коллекции",
|
"LabelCollections": "Коллекции",
|
||||||
"LabelComplete": "Завершить",
|
"LabelComplete": "Завершить",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "Длина",
|
"LabelDuration": "Длина",
|
||||||
"LabelDurationFound": "Найденная длина:",
|
"LabelDurationFound": "Найденная длина:",
|
||||||
"LabelEdit": "Редактировать",
|
"LabelEdit": "Редактировать",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "Включить",
|
"LabelEnable": "Включить",
|
||||||
"LabelEnd": "Конец",
|
"LabelEnd": "Конец",
|
||||||
"LabelEpisode": "Эпизод",
|
"LabelEpisode": "Эпизод",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "Закончен",
|
"LabelFinished": "Закончен",
|
||||||
"LabelFolder": "Папка",
|
"LabelFolder": "Папка",
|
||||||
"LabelFolders": "Папки",
|
"LabelFolders": "Папки",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Жанр",
|
"LabelGenre": "Жанр",
|
||||||
"LabelGenres": "Жанры",
|
"LabelGenres": "Жанры",
|
||||||
"LabelHardDeleteFile": "Жесткое удаление файла",
|
"LabelHardDeleteFile": "Жесткое удаление файла",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "Тип медиа",
|
"LabelMediaType": "Тип медиа",
|
||||||
"LabelMetadataProvider": "Провайдер",
|
"LabelMetadataProvider": "Провайдер",
|
||||||
"LabelMetaTag": "Мета тег",
|
"LabelMetaTag": "Мета тег",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "Минуты",
|
"LabelMinute": "Минуты",
|
||||||
"LabelMissing": "Потеряно",
|
"LabelMissing": "Потеряно",
|
||||||
"LabelMissingParts": "Потерянные части",
|
"LabelMissingParts": "Потерянные части",
|
||||||
"LabelMore": "Еще",
|
"LabelMore": "Еще",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "Имя",
|
"LabelName": "Имя",
|
||||||
"LabelNarrator": "Читает",
|
"LabelNarrator": "Читает",
|
||||||
"LabelNarrators": "Чтецы",
|
"LabelNarrators": "Чтецы",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "Теги",
|
"LabelTags": "Теги",
|
||||||
"LabelTagsAccessibleToUser": "Теги доступные для пользователя",
|
"LabelTagsAccessibleToUser": "Теги доступные для пользователя",
|
||||||
"LabelTasks": "Запущенные задачи",
|
"LabelTasks": "Запущенные задачи",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "Время прослушивания",
|
"LabelTimeListened": "Время прослушивания",
|
||||||
"LabelTimeListenedToday": "Время прослушивания сегодня",
|
"LabelTimeListenedToday": "Время прослушивания сегодня",
|
||||||
"LabelTimeRemaining": "{0} осталось",
|
"LabelTimeRemaining": "{0} осталось",
|
||||||
|
@ -183,11 +183,15 @@
|
|||||||
"LabelBackupsMaxBackupSizeHelp": "为了防止错误配置, 如果备份超过配置的大小, 备份将失败.",
|
"LabelBackupsMaxBackupSizeHelp": "为了防止错误配置, 如果备份超过配置的大小, 备份将失败.",
|
||||||
"LabelBackupsNumberToKeep": "要保留的备份个数",
|
"LabelBackupsNumberToKeep": "要保留的备份个数",
|
||||||
"LabelBackupsNumberToKeepHelp": "一次只能删除一个备份, 因此如果你已经有超过此数量的备份, 则应手动删除它们.",
|
"LabelBackupsNumberToKeepHelp": "一次只能删除一个备份, 因此如果你已经有超过此数量的备份, 则应手动删除它们.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "图书",
|
"LabelBooks": "图书",
|
||||||
"LabelChangePassword": "修改密码",
|
"LabelChangePassword": "修改密码",
|
||||||
|
"LabelChannels": "Channels",
|
||||||
|
"LabelChapters": "Chapters",
|
||||||
"LabelChaptersFound": "找到的章节",
|
"LabelChaptersFound": "找到的章节",
|
||||||
"LabelChapterTitle": "章节标题",
|
"LabelChapterTitle": "章节标题",
|
||||||
"LabelClosePlayer": "关闭播放器",
|
"LabelClosePlayer": "关闭播放器",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "折叠系列",
|
"LabelCollapseSeries": "折叠系列",
|
||||||
"LabelCollections": "收藏",
|
"LabelCollections": "收藏",
|
||||||
"LabelComplete": "已完成",
|
"LabelComplete": "已完成",
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"LabelDuration": "持续时间",
|
"LabelDuration": "持续时间",
|
||||||
"LabelDurationFound": "找到持续时间:",
|
"LabelDurationFound": "找到持续时间:",
|
||||||
"LabelEdit": "编辑",
|
"LabelEdit": "编辑",
|
||||||
|
"LabelEmbeddedCover": "Embedded Cover",
|
||||||
"LabelEnable": "启用",
|
"LabelEnable": "启用",
|
||||||
"LabelEnd": "结束",
|
"LabelEnd": "结束",
|
||||||
"LabelEpisode": "剧集",
|
"LabelEpisode": "剧集",
|
||||||
@ -230,6 +235,7 @@
|
|||||||
"LabelFinished": "已听完",
|
"LabelFinished": "已听完",
|
||||||
"LabelFolder": "文件夹",
|
"LabelFolder": "文件夹",
|
||||||
"LabelFolders": "文件夹",
|
"LabelFolders": "文件夹",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "流派",
|
"LabelGenre": "流派",
|
||||||
"LabelGenres": "流派",
|
"LabelGenres": "流派",
|
||||||
"LabelHardDeleteFile": "完全删除文件",
|
"LabelHardDeleteFile": "完全删除文件",
|
||||||
@ -271,10 +277,12 @@
|
|||||||
"LabelMediaType": "媒体类型",
|
"LabelMediaType": "媒体类型",
|
||||||
"LabelMetadataProvider": "元数据提供者",
|
"LabelMetadataProvider": "元数据提供者",
|
||||||
"LabelMetaTag": "元数据标签",
|
"LabelMetaTag": "元数据标签",
|
||||||
|
"LabelMetaTags": "Meta Tags",
|
||||||
"LabelMinute": "分钟",
|
"LabelMinute": "分钟",
|
||||||
"LabelMissing": "丢失",
|
"LabelMissing": "丢失",
|
||||||
"LabelMissingParts": "丢失的部分",
|
"LabelMissingParts": "丢失的部分",
|
||||||
"LabelMore": "更多",
|
"LabelMore": "更多",
|
||||||
|
"LabelMoreInfo": "More Info",
|
||||||
"LabelName": "名称",
|
"LabelName": "名称",
|
||||||
"LabelNarrator": "演播者",
|
"LabelNarrator": "演播者",
|
||||||
"LabelNarrators": "演播者",
|
"LabelNarrators": "演播者",
|
||||||
@ -405,6 +413,7 @@
|
|||||||
"LabelTags": "标签",
|
"LabelTags": "标签",
|
||||||
"LabelTagsAccessibleToUser": "用户可访问的标签",
|
"LabelTagsAccessibleToUser": "用户可访问的标签",
|
||||||
"LabelTasks": "正在运行的任务",
|
"LabelTasks": "正在运行的任务",
|
||||||
|
"LabelTimeBase": "Time Base",
|
||||||
"LabelTimeListened": "收听时间",
|
"LabelTimeListened": "收听时间",
|
||||||
"LabelTimeListenedToday": "今日收听的时间",
|
"LabelTimeListenedToday": "今日收听的时间",
|
||||||
"LabelTimeRemaining": "剩余 {0}",
|
"LabelTimeRemaining": "剩余 {0}",
|
||||||
|
@ -66,7 +66,15 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete(req, res) {
|
async delete(req, res) {
|
||||||
|
const hardDelete = req.query.hard == 1 // Delete from file system
|
||||||
|
const libraryItemPath = req.libraryItem.path
|
||||||
await this.handleDeleteLibraryItem(req.libraryItem)
|
await this.handleDeleteLibraryItem(req.libraryItem)
|
||||||
|
if (hardDelete) {
|
||||||
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
|
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
||||||
|
})
|
||||||
|
}
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,19 +300,27 @@ class LibraryItemController {
|
|||||||
Logger.warn(`[LibraryItemController] User attempted to delete without permission`, req.user)
|
Logger.warn(`[LibraryItemController] User attempted to delete without permission`, req.user)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
const hardDelete = req.query.hard == 1 // Delete files from filesystem
|
||||||
|
|
||||||
var { libraryItemIds } = req.body
|
const { libraryItemIds } = req.body
|
||||||
if (!libraryItemIds || !libraryItemIds.length) {
|
if (!libraryItemIds || !libraryItemIds.length) {
|
||||||
return res.sendStatus(500)
|
return res.sendStatus(500)
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemsToDelete = this.db.libraryItems.filter(li => libraryItemIds.includes(li.id))
|
const itemsToDelete = this.db.libraryItems.filter(li => libraryItemIds.includes(li.id))
|
||||||
if (!itemsToDelete.length) {
|
if (!itemsToDelete.length) {
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
for (let i = 0; i < itemsToDelete.length; i++) {
|
for (let i = 0; i < itemsToDelete.length; i++) {
|
||||||
|
const libraryItemPath = itemsToDelete[i].path
|
||||||
Logger.info(`[LibraryItemController] Deleting Library Item "${itemsToDelete[i].media.metadata.title}"`)
|
Logger.info(`[LibraryItemController] Deleting Library Item "${itemsToDelete[i].media.metadata.title}"`)
|
||||||
await this.handleDeleteLibraryItem(itemsToDelete[i])
|
await this.handleDeleteLibraryItem(itemsToDelete[i])
|
||||||
|
if (hardDelete) {
|
||||||
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
|
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
@ -489,7 +505,9 @@ class LibraryItemController {
|
|||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.remove(libraryFile.metadata.path)
|
await fs.remove(libraryFile.metadata.path).catch((error) => {
|
||||||
|
Logger.error(`[LibraryItemController] Failed to delete library file at "${libraryFile.metadata.path}"`, error)
|
||||||
|
})
|
||||||
req.libraryItem.removeLibraryFile(req.params.ino)
|
req.libraryItem.removeLibraryFile(req.params.ino)
|
||||||
|
|
||||||
if (req.libraryItem.media.removeFileWithInode(req.params.ino)) {
|
if (req.libraryItem.media.removeFileWithInode(req.params.ino)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user