mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-05 13:01:12 +01:00
Update:More localization strings #1103
This commit is contained in:
parent
eb463a2958
commit
faac6f677a
@ -2,19 +2,19 @@
|
|||||||
<div class="w-full h-20 md:h-10 relative">
|
<div class="w-full h-20 md:h-10 relative">
|
||||||
<div class="flex md:hidden h-10 items-center">
|
<div class="flex md:hidden h-10 items-center">
|
||||||
<nuxt-link :to="`/library/${currentLibraryId}`" class="flex-grow h-full flex justify-center items-center" :class="isHomePage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
<nuxt-link :to="`/library/${currentLibraryId}`" class="flex-grow h-full flex justify-center items-center" :class="isHomePage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||||
<p class="text-sm">Home</p>
|
<p class="text-sm">{{ $strings.ButtonHome }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<nuxt-link :to="`/library/${currentLibraryId}/bookshelf`" class="flex-grow h-full flex justify-center items-center" :class="isLibraryPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
<nuxt-link :to="`/library/${currentLibraryId}/bookshelf`" class="flex-grow h-full flex justify-center items-center" :class="isLibraryPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||||
<p class="text-sm">Library</p>
|
<p class="text-sm">{{ $strings.ButtonLibrary }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="flex-grow h-full flex justify-center items-center" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="flex-grow h-full flex justify-center items-center" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||||
<p class="text-sm">Series</p>
|
<p class="text-sm">{{ $strings.ButtonSeries }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="flex-grow h-full flex justify-center items-center" :class="isCollectionsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="flex-grow h-full flex justify-center items-center" :class="isCollectionsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||||
<p class="text-sm">Collections</p>
|
<p class="text-sm">{{ $strings.ButtonCollections }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||||
<p class="text-sm">Search</p>
|
<p class="text-sm">{{ $strings.ButtonSearch }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
<div id="toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-30 flex items-center justify-end md:justify-start px-2 md:px-8">
|
<div id="toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-30 flex items-center justify-end md:justify-start px-2 md:px-8">
|
||||||
@ -28,42 +28,37 @@
|
|||||||
<span class="font-mono">{{ numShowing }}</span>
|
<span class="font-mono">{{ numShowing }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-checkbox v-model="settings.collapseBookSeries" label="Collapse Series" checkbox-bg="bg"
|
<ui-checkbox v-model="settings.collapseBookSeries" :label="$strings.LabelCollapseSeries" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseBookSeries" />
|
||||||
check-color="white" small class="mr-2" @input="updateCollapseBookSeries" />
|
<ui-btn color="primary" small :loading="processingSeries" class="flex items-center ml-1 sm:ml-4" @click="markSeriesFinished">
|
||||||
<ui-btn color="primary" small :loading="processingSeries" class="flex items-center ml-1 sm:ml-4"
|
|
||||||
@click="markSeriesFinished">
|
|
||||||
<div class="h-5 w-5">
|
<div class="h-5 w-5">
|
||||||
<svg v-if="isSeriesFinished" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
<svg v-if="isSeriesFinished" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(63, 181, 68)">
|
||||||
fill="rgb(63, 181, 68)">
|
<path d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z" />
|
||||||
<path
|
|
||||||
d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
<svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
<svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path
|
<path d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-7 19.6l-7-4.66V3h14v12.93l-7 4.67zm-2.01-7.42l-2.58-2.59L6 12l4 4 8-8-1.42-1.42z" />
|
||||||
d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-7 19.6l-7-4.66V3h14v12.93l-7 4.67zm-2.01-7.42l-2.58-2.59L6 12l4 4 8-8-1.42-1.42z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span class="pl-2"> Mark Series {{ isSeriesFinished ? 'Not Finished' : 'Finished' }}</span>
|
<span class="pl-2"> {{ $strings.LabelMarkSeries }} {{ isSeriesFinished ? $strings.LabelNotFinished : $strings.LabelFinished }}</span>
|
||||||
</ui-btn>
|
</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow hidden sm:inline-block" />
|
<div class="flex-grow hidden sm:inline-block" />
|
||||||
|
|
||||||
<ui-checkbox v-if="isLibraryPage && !isPodcastLibrary" v-model="settings.collapseSeries" label="Collapse Series" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseSeries" />
|
<ui-checkbox v-if="isLibraryPage && !isPodcastLibrary" v-model="settings.collapseSeries" :label="$strings.LabelCollapseSeries" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseSeries" />
|
||||||
<controls-library-filter-select v-if="isLibraryPage" v-model="settings.filterBy" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateFilter" />
|
<controls-library-filter-select v-if="isLibraryPage" v-model="settings.filterBy" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateFilter" />
|
||||||
<controls-library-sort-select v-if="isLibraryPage" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateOrder" />
|
<controls-library-sort-select v-if="isLibraryPage" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateOrder" />
|
||||||
<controls-library-filter-select v-if="isSeriesPage" v-model="seriesFilterBy" is-series class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateSeriesFilter" />
|
<controls-library-filter-select v-if="isSeriesPage" v-model="seriesFilterBy" is-series class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateSeriesFilter" />
|
||||||
<controls-sort-select v-if="isSeriesPage" v-model="seriesSortBy" :descending.sync="seriesSortDesc" :items="seriesSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateSeriesSort" />
|
<controls-sort-select v-if="isSeriesPage" v-model="seriesSortBy" :descending.sync="seriesSortDesc" :items="seriesSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateSeriesSort" />
|
||||||
|
|
||||||
<ui-btn v-if="isIssuesFilter && userCanDelete" :loading="processingIssues" color="error" small class="ml-4" @click="removeAllIssues">Remove All {{ numShowing }} {{ entityName }}</ui-btn>
|
<ui-btn v-if="isIssuesFilter && userCanDelete" :loading="processingIssues" color="error" small class="ml-4" @click="removeAllIssues">{{ $strings.ButtonRemoveAll }} {{ numShowing }} {{ entityName }}</ui-btn>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="page === 'search'">
|
<template v-else-if="page === 'search'">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<p>Search results for "{{ searchQuery }}"</p>
|
<p>{{ $strings.MessageSearchResultsFor }} "{{ searchQuery }}"</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="page === 'authors'">
|
<template v-else-if="page === 'authors'">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="userCanUpdate && authors && authors.length" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">Match All Authors</ui-btn>
|
<ui-btn v-if="userCanUpdate && authors && authors.length" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -150,10 +145,10 @@ export default {
|
|||||||
return this.totalEntities
|
return this.totalEntities
|
||||||
},
|
},
|
||||||
entityName() {
|
entityName() {
|
||||||
if (this.isPodcastLibrary) return 'Podcasts'
|
if (this.isPodcastLibrary) return this.$strings.LabelPodcasts
|
||||||
if (!this.page) return 'Books'
|
if (!this.page) return this.$strings.LabelBooks
|
||||||
if (this.isSeriesPage) return 'Series'
|
if (this.isSeriesPage) return this.$strings.LabelSeries
|
||||||
if (this.isCollectionsPage) return 'Collections'
|
if (this.isCollectionsPage) return this.$strings.LabelCollections
|
||||||
return ''
|
return ''
|
||||||
},
|
},
|
||||||
seriesName() {
|
seriesName() {
|
||||||
|
@ -47,7 +47,7 @@ export default {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 'config-stats',
|
id: 'config-stats',
|
||||||
title: 'Your Stats',
|
title: this.$strings.HeaderYourStats,
|
||||||
path: '/config/stats'
|
path: '/config/stats'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -55,37 +55,37 @@ export default {
|
|||||||
const configRoutes = [
|
const configRoutes = [
|
||||||
{
|
{
|
||||||
id: 'config',
|
id: 'config',
|
||||||
title: 'Settings',
|
title: this.$strings.HeaderSettings,
|
||||||
path: '/config'
|
path: '/config'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-libraries',
|
id: 'config-libraries',
|
||||||
title: 'Libraries',
|
title: this.$strings.HeaderLibraries,
|
||||||
path: '/config/libraries'
|
path: '/config/libraries'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-users',
|
id: 'config-users',
|
||||||
title: 'Users',
|
title: this.$strings.HeaderUsers,
|
||||||
path: '/config/users'
|
path: '/config/users'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-sessions',
|
id: 'config-sessions',
|
||||||
title: 'Listening Sessions',
|
title: this.$strings.HeaderListeningSessions,
|
||||||
path: '/config/sessions'
|
path: '/config/sessions'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-backups',
|
id: 'config-backups',
|
||||||
title: 'Backups',
|
title: this.$strings.HeaderBackups,
|
||||||
path: '/config/backups'
|
path: '/config/backups'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-log',
|
id: 'config-log',
|
||||||
title: 'Logs',
|
title: this.$strings.HeaderLogs,
|
||||||
path: '/config/log'
|
path: '/config/log'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'config-notifications',
|
id: 'config-notifications',
|
||||||
title: 'Notifications',
|
title: this.$strings.HeaderNotifications,
|
||||||
path: '/config/notifications'
|
path: '/config/notifications'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -93,12 +93,12 @@ export default {
|
|||||||
if (this.currentLibraryId) {
|
if (this.currentLibraryId) {
|
||||||
configRoutes.push({
|
configRoutes.push({
|
||||||
id: 'config-library-stats',
|
id: 'config-library-stats',
|
||||||
title: 'Library Stats',
|
title: this.$strings.HeaderLibraryStats,
|
||||||
path: '/config/library-stats'
|
path: '/config/library-stats'
|
||||||
})
|
})
|
||||||
configRoutes.push({
|
configRoutes.push({
|
||||||
id: 'config-stats',
|
id: 'config-stats',
|
||||||
title: 'Your Stats',
|
title: this.$strings.HeaderYourStats,
|
||||||
path: '/config/stats'
|
path: '/config/stats'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ export default {
|
|||||||
},
|
},
|
||||||
closeDrawer() {
|
closeDrawer() {
|
||||||
this.$emit('update:isOpen', false)
|
this.$emit('update:isOpen', false)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -15,41 +15,41 @@
|
|||||||
|
|
||||||
<div class="flex my-2 -mx-2">
|
<div class="flex my-2 -mx-2">
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-model="itemData.title" :disabled="processing" label="Title" @input="titleUpdated" />
|
<ui-text-input-with-label v-model="itemData.title" :disabled="processing" :label="$strings.LabelTitle" @input="titleUpdated" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-if="!isPodcast" v-model="itemData.author" :disabled="processing" label="Author" />
|
<ui-text-input-with-label v-if="!isPodcast" v-model="itemData.author" :disabled="processing" :label="$strings.LabelAuthor" />
|
||||||
<div v-else class="w-full">
|
<div v-else class="w-full">
|
||||||
<p class="px-1 text-sm font-semibold">Directory <em class="font-normal text-xs pl-2">(auto)</em></p>
|
<p class="px-1 text-sm font-semibold">{{ $strings.LabelDirectory }} <em class="font-normal text-xs pl-2">(auto)</em></p>
|
||||||
<ui-text-input :value="directory" disabled class="w-full font-mono text-xs" style="height: 38px" />
|
<ui-text-input :value="directory" disabled class="w-full font-mono text-xs" style="height: 38px" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isPodcast" class="flex my-2 -mx-2">
|
<div v-if="!isPodcast" class="flex my-2 -mx-2">
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-model="itemData.series" :disabled="processing" label="Series" note="(optional)" />
|
<ui-text-input-with-label v-model="itemData.series" :disabled="processing" :label="$strings.LabelSeries" note="(optional)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<p class="px-1 text-sm font-semibold">Directory <em class="font-normal text-xs pl-2">(auto)</em></p>
|
<p class="px-1 text-sm font-semibold">{{ $strings.LabelDirectory }} <em class="font-normal text-xs pl-2">(auto)</em></p>
|
||||||
<ui-text-input :value="directory" disabled class="w-full font-mono text-xs" style="height: 38px" />
|
<ui-text-input :value="directory" disabled class="w-full font-mono text-xs" style="height: 38px" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tables-uploaded-files-table :files="item.itemFiles" title="Item Files" class="mt-8" />
|
<tables-uploaded-files-table :files="item.itemFiles" :title="$strings.HeaderItemFiles" class="mt-8" />
|
||||||
<tables-uploaded-files-table v-if="item.otherFiles.length" title="Other Files" :files="item.otherFiles" />
|
<tables-uploaded-files-table v-if="item.otherFiles.length" :title="$strings.HeaderOtherFiles" :files="item.otherFiles" />
|
||||||
<tables-uploaded-files-table v-if="item.ignoredFiles.length" title="Ignored Files" :files="item.ignoredFiles" />
|
<tables-uploaded-files-table v-if="item.ignoredFiles.length" :title="$strings.HeaderIgnoredFiles" :files="item.ignoredFiles" />
|
||||||
</template>
|
</template>
|
||||||
<widgets-alert v-if="uploadSuccess" type="success">
|
<widgets-alert v-if="uploadSuccess" type="success">
|
||||||
<p class="text-base">Successfully Uploaded!</p>
|
<p class="text-base">{{ $strings.MessageUploaderItemSuccess }}</p>
|
||||||
</widgets-alert>
|
</widgets-alert>
|
||||||
<widgets-alert v-if="uploadFailed" type="error">
|
<widgets-alert v-if="uploadFailed" type="error">
|
||||||
<p class="text-base">Failed to upload</p>
|
<p class="text-base">{{ $strings.MessageUploaderItemFailed }}</p>
|
||||||
</widgets-alert>
|
</widgets-alert>
|
||||||
|
|
||||||
<div v-if="isUploading" class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-20">
|
<div v-if="isUploading" class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-20">
|
||||||
<ui-loading-indicator text="Uploading..." />
|
<ui-loading-indicator :text="$strings.MessageUploading" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sm:w-80 w-full relative">
|
<div class="sm:w-80 w-full relative">
|
||||||
<form @submit.prevent="submitSearch">
|
<form @submit.prevent="submitSearch">
|
||||||
<ui-text-input ref="input" v-model="search" :placeholder="$strings.SearchPlaceholder" @input="inputUpdate" @focus="focussed" @blur="blurred" class="w-full h-8 text-sm" />
|
<ui-text-input ref="input" v-model="search" :placeholder="$strings.PlaceholderSearch" @input="inputUpdate" @focus="focussed" @blur="blurred" class="w-full h-8 text-sm" />
|
||||||
</form>
|
</form>
|
||||||
<div class="absolute top-0 right-0 bottom-0 h-full flex items-center px-2 text-gray-400 cursor-pointer" @click="clickClear">
|
<div class="absolute top-0 right-0 bottom-0 h-full flex items-center px-2 text-gray-400 cursor-pointer" @click="clickClear">
|
||||||
<span v-if="!search" class="material-icons" style="font-size: 1.2rem">search</span>
|
<span v-if="!search" class="material-icons" style="font-size: 1.2rem">search</span>
|
||||||
|
@ -10,28 +10,28 @@
|
|||||||
<div class="w-full p-8">
|
<div class="w-full p-8">
|
||||||
<div class="flex py-2">
|
<div class="flex py-2">
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-model="newUser.username" label="Username" />
|
<ui-text-input-with-label v-model="newUser.username" :label="$strings.LabelUsername" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 px-2">
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-if="!isEditingRoot" v-model="newUser.password" :label="isNew ? 'Password' : 'Change Password'" type="password" />
|
<ui-text-input-with-label v-if="!isEditingRoot" v-model="newUser.password" :label="isNew ? $strings.LabelPassword : $strings.LabelChangePassword" type="password" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!isEditingRoot" class="flex py-2">
|
<div v-show="!isEditingRoot" class="flex py-2">
|
||||||
<div class="px-2 w-52">
|
<div class="px-2 w-52">
|
||||||
<ui-dropdown v-model="newUser.type" label="Account Type" :disabled="isEditingRoot" :items="accountTypes" @input="userTypeUpdated" />
|
<ui-dropdown v-model="newUser.type" :label="$strings.LabelAccountType" :disabled="isEditingRoot" :items="accountTypes" @input="userTypeUpdated" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<div class="flex items-center pt-4 px-2">
|
<div class="flex items-center pt-4 px-2">
|
||||||
<p class="px-3 font-semibold" :class="isEditingRoot ? 'text-gray-300' : ''">Is Active</p>
|
<p class="px-3 font-semibold" :class="isEditingRoot ? 'text-gray-300' : ''">{{ $strings.LabelEnable }}</p>
|
||||||
<ui-toggle-switch v-model="newUser.isActive" :disabled="isEditingRoot" />
|
<ui-toggle-switch v-model="newUser.isActive" :disabled="isEditingRoot" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!isEditingRoot && newUser.permissions" class="w-full border-t border-b border-black-200 py-2 px-3 mt-4">
|
<div v-if="!isEditingRoot && newUser.permissions" class="w-full border-t border-b border-black-200 py-2 px-3 mt-4">
|
||||||
<p class="text-lg mb-2 font-semibold">Permissions</p>
|
<p class="text-lg mb-2 font-semibold">{{ $strings.HeaderPermissions }}</p>
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Download</p>
|
<p>{{ $strings.LabelPermissionsDownload }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.download" />
|
<ui-toggle-switch v-model="newUser.permissions.download" />
|
||||||
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Update</p>
|
<p>{{ $strings.LabelPermissionsUpdate }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.update" />
|
<ui-toggle-switch v-model="newUser.permissions.update" />
|
||||||
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Delete</p>
|
<p>{{ $strings.LabelPermissionsDelete }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.delete" />
|
<ui-toggle-switch v-model="newUser.permissions.delete" />
|
||||||
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Upload</p>
|
<p>{{ $strings.LabelPermissionsUpload }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.upload" />
|
<ui-toggle-switch v-model="newUser.permissions.upload" />
|
||||||
@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Access Explicit Content</p>
|
<p>{{ $strings.LabelPermissionsAccessExplicitContent }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.accessExplicitContent" />
|
<ui-toggle-switch v-model="newUser.permissions.accessExplicitContent" />
|
||||||
@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Access All Libraries</p>
|
<p>{{ $strings.LabelPermissionsAccessAllLibraries }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.accessAllLibraries" @input="accessAllLibrariesToggled" />
|
<ui-toggle-switch v-model="newUser.permissions.accessAllLibraries" @input="accessAllLibrariesToggled" />
|
||||||
@ -84,26 +84,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!newUser.permissions.accessAllLibraries" class="my-4">
|
<div v-if="!newUser.permissions.accessAllLibraries" class="my-4">
|
||||||
<ui-multi-select-dropdown v-model="newUser.librariesAccessible" :items="libraryItems" label="Libraries Accessible to User" />
|
<ui-multi-select-dropdown v-model="newUser.librariesAccessible" :items="libraryItems" :label="$strings.LabelLibrariesAccessibleToUser" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-cen~ter my-2 max-w-md">
|
<div class="flex items-cen~ter my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p>Can Access All Tags</p>
|
<p>{{ $strings.LabelPermissionsAccessAllTags }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<ui-toggle-switch v-model="newUser.permissions.accessAllTags" @input="accessAllTagsToggled" />
|
<ui-toggle-switch v-model="newUser.permissions.accessAllTags" @input="accessAllTagsToggled" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!newUser.permissions.accessAllTags" class="my-4">
|
<div v-if="!newUser.permissions.accessAllTags" class="my-4">
|
||||||
<ui-multi-select-dropdown v-model="newUser.itemTagsAccessible" :items="itemTags" label="Tags Accessible to User" />
|
<ui-multi-select-dropdown v-model="newUser.itemTagsAccessible" :items="itemTags" :label="$strings.LabelTagsAccessibleToUser" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex pt-4 px-2">
|
<div class="flex pt-4 px-2">
|
||||||
<ui-btn v-if="isEditingRoot" to="/account">Change Root Password</ui-btn>
|
<ui-btn v-if="isEditingRoot" to="/account">{{ $strings.ButtonChangeRootPassword }}</ui-btn>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn color="success" type="submit">Submit</ui-btn>
|
<ui-btn color="success" type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -165,7 +165,7 @@ export default {
|
|||||||
return this.$store.state.user.user
|
return this.$store.state.user.user
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return this.isNew ? 'Add New Account' : `Update ${(this.account || {}).username}`
|
return this.isNew ? this.$strings.HeaderNewAccount : this.$strings.HeaderUpdateAccount
|
||||||
},
|
},
|
||||||
isEditingRoot() {
|
isEditingRoot() {
|
||||||
return this.account && this.account.type === 'root'
|
return this.account && this.account.type === 'root'
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<modals-modal v-model="show" name="edit-collection" :width="700" :height="'unset'" :processing="processing">
|
<modals-modal v-model="show" name="edit-collection" :width="700" :height="'unset'" :processing="processing">
|
||||||
<template #outer>
|
<template #outer>
|
||||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||||
<p class="font-book text-3xl text-white truncate">Collection</p>
|
<p class="font-book text-3xl text-white truncate">{{ $strings.HeaderCollection }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="p-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh">
|
<div class="p-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh">
|
||||||
@ -14,15 +14,15 @@
|
|||||||
<!-- <ui-btn type="button" @click="showImageUploader = true">Upload</ui-btn> -->
|
<!-- <ui-btn type="button" @click="showImageUploader = true">Upload</ui-btn> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-4">
|
<div class="flex-grow px-4">
|
||||||
<ui-text-input-with-label v-model="newCollectionName" label="Name" class="mb-2" />
|
<ui-text-input-with-label v-model="newCollectionName" :label="$strings.LabelName" class="mb-2" />
|
||||||
|
|
||||||
<ui-textarea-with-label v-model="newCollectionDescription" label="Description" />
|
<ui-textarea-with-label v-model="newCollectionDescription" :label="$strings.LabelDescription" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute bottom-0 left-0 right-0 w-full py-2 px-4 flex">
|
<div class="absolute bottom-0 left-0 right-0 w-full py-2 px-4 flex">
|
||||||
<ui-btn v-if="userCanDelete" small color="error" type="button" @click.stop="removeClick">Remove</ui-btn>
|
<ui-btn v-if="userCanDelete" small color="error" type="button" @click.stop="removeClick">{{ $strings.ButtonRemove }}</ui-btn>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn color="success" type="submit">Save</ui-btn>
|
<ui-btn color="success" type="submit">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
<div class="bg-bg rounded-lg px-2 py-6 sm:p-6 md:p-8" @click.stop>
|
<div class="bg-bg rounded-lg px-2 py-6 sm:p-6 md:p-8" @click.stop>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-grow p-1 min-w-48 sm:min-w-64 md:min-w-80">
|
<div class="flex-grow p-1 min-w-48 sm:min-w-64 md:min-w-80">
|
||||||
<ui-input-dropdown ref="newSeriesSelect" v-model="selectedSeries.name" :items="existingSeriesNames" :disabled="!isNewSeries" label="Series Name" />
|
<ui-input-dropdown ref="newSeriesSelect" v-model="selectedSeries.name" :items="existingSeriesNames" :disabled="!isNewSeries" :label="$strings.LabelSeriesName" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-24 sm:w-28 md:w-40 p-1">
|
<div class="w-24 sm:w-28 md:w-40 p-1">
|
||||||
<ui-text-input-with-label ref="sequenceInput" v-model="selectedSeries.sequence" label="Sequence" />
|
<ui-text-input-with-label ref="sequenceInput" v-model="selectedSeries.sequence" :label="$strings.LabelSequence" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-2 p-1">
|
<div class="flex justify-end mt-2 p-1">
|
||||||
<ui-btn type="submit">Save</ui-btn>
|
<ui-btn type="submit">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -31,55 +31,7 @@ export default {
|
|||||||
processing: false,
|
processing: false,
|
||||||
libraryItem: null,
|
libraryItem: null,
|
||||||
availableHeight: 0,
|
availableHeight: 0,
|
||||||
marginTop: 0,
|
marginTop: 0
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
id: 'details',
|
|
||||||
title: 'Details',
|
|
||||||
component: 'modals-item-tabs-details'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'cover',
|
|
||||||
title: 'Cover',
|
|
||||||
component: 'modals-item-tabs-cover'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'chapters',
|
|
||||||
title: 'Chapters',
|
|
||||||
component: 'modals-item-tabs-chapters',
|
|
||||||
mediaType: 'book'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'episodes',
|
|
||||||
title: 'Episodes',
|
|
||||||
component: 'modals-item-tabs-episodes',
|
|
||||||
mediaType: 'podcast'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'files',
|
|
||||||
title: 'Files',
|
|
||||||
component: 'modals-item-tabs-files'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'match',
|
|
||||||
title: 'Match',
|
|
||||||
component: 'modals-item-tabs-match'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tools',
|
|
||||||
title: 'Tools',
|
|
||||||
component: 'modals-item-tabs-tools',
|
|
||||||
mediaType: 'book',
|
|
||||||
admin: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'schedule',
|
|
||||||
title: 'Schedule',
|
|
||||||
component: 'modals-item-tabs-schedule',
|
|
||||||
mediaType: 'podcast',
|
|
||||||
admin: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -122,6 +74,56 @@ export default {
|
|||||||
this.$store.commit('setEditModalTab', val)
|
this.$store.commit('setEditModalTab', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
tabs() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'details',
|
||||||
|
title: this.$strings.HeaderDetails,
|
||||||
|
component: 'modals-item-tabs-details'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cover',
|
||||||
|
title: this.$strings.HeaderCover,
|
||||||
|
component: 'modals-item-tabs-cover'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'chapters',
|
||||||
|
title: this.$strings.HeaderChapters,
|
||||||
|
component: 'modals-item-tabs-chapters',
|
||||||
|
mediaType: 'book'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'episodes',
|
||||||
|
title: this.$strings.HeaderEpisodes,
|
||||||
|
component: 'modals-item-tabs-episodes',
|
||||||
|
mediaType: 'podcast'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'files',
|
||||||
|
title: this.$strings.HeaderFiles,
|
||||||
|
component: 'modals-item-tabs-files'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'match',
|
||||||
|
title: this.$strings.HeaderMatch,
|
||||||
|
component: 'modals-item-tabs-match'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tools',
|
||||||
|
title: this.$strings.HeaderTools,
|
||||||
|
component: 'modals-item-tabs-tools',
|
||||||
|
mediaType: 'book',
|
||||||
|
admin: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'schedule',
|
||||||
|
title: this.$strings.HeaderSchedule,
|
||||||
|
component: 'modals-item-tabs-schedule',
|
||||||
|
mediaType: 'podcast',
|
||||||
|
admin: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
showExperimentalFeatures() {
|
showExperimentalFeatures() {
|
||||||
return this.$store.state.showExperimentalFeatures
|
return this.$store.state.showExperimentalFeatures
|
||||||
},
|
},
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<div class="w-full mb-4">
|
<div class="w-full mb-4">
|
||||||
<tables-chapters-table v-if="chapters.length" :library-item="libraryItem" keep-open />
|
<tables-chapters-table v-if="chapters.length" :library-item="libraryItem" keep-open />
|
||||||
<div v-if="!chapters.length" class="py-4 text-center">
|
<div v-if="!chapters.length" class="py-4 text-center">
|
||||||
<p class="mb-8 text-xl">No Chapters</p>
|
<p class="mb-8 text-xl">{{ $strings.MessageNoChapters }}</p>
|
||||||
<ui-btn v-if="userCanUpdate" :to="`/audiobook/${libraryItem.id}/chapters`">Add Chapters</ui-btn>
|
<ui-btn v-if="userCanUpdate" :to="`/audiobook/${libraryItem.id}/chapters`">{{ $strings.ButtonAddChapters }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,11 +14,14 @@
|
|||||||
<div class="flex-grow sm:pl-2 md:pl-6 sm:pr-2 mt-2 md:mt-0">
|
<div class="flex-grow sm:pl-2 md:pl-6 sm:pr-2 mt-2 md:mt-0">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div v-if="userCanUpload" class="w-10 md:w-40 pr-2 pt-4 md:min-w-32">
|
<div v-if="userCanUpload" class="w-10 md:w-40 pr-2 pt-4 md:min-w-32">
|
||||||
<ui-file-input ref="fileInput" @change="fileUploadSelected"><span class="hidden md:inline-block">Upload Cover</span><span class="material-icons inline-block md:!hidden">upload</span></ui-file-input>
|
<ui-file-input ref="fileInput" @change="fileUploadSelected"
|
||||||
|
><span class="hidden md:inline-block">{{ $strings.ButtonUploadCover }}</span
|
||||||
|
><span class="material-icons inline-block md:!hidden">upload</span></ui-file-input
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<form @submit.prevent="submitForm" class="flex flex-grow">
|
<form @submit.prevent="submitForm" class="flex flex-grow">
|
||||||
<ui-text-input-with-label v-model="imageUrl" label="Cover Image URL" />
|
<ui-text-input-with-label v-model="imageUrl" :label="$strings.LabelCoverImageURL" />
|
||||||
<ui-btn color="success" type="submit" :padding-x="4" class="mt-5 ml-2 sm:ml-3 w-24">Update</ui-btn>
|
<ui-btn color="success" type="submit" :padding-x="4" class="mt-5 ml-2 sm:ml-3 w-24">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -26,7 +29,7 @@
|
|||||||
<div class="flex items-center justify-center py-2">
|
<div class="flex items-center justify-center py-2">
|
||||||
<p>{{ localCovers.length }} local image{{ localCovers.length !== 1 ? 's' : '' }}</p>
|
<p>{{ localCovers.length }} local image{{ localCovers.length !== 1 ? 's' : '' }}</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn small @click="showLocalCovers = !showLocalCovers">{{ showLocalCovers ? 'Hide' : 'Show' }}</ui-btn>
|
<ui-btn small @click="showLocalCovers = !showLocalCovers">{{ showLocalCovers ? $strings.ButtonHide : $strings.ButtonShow }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showLocalCovers" class="flex items-center justify-center">
|
<div v-if="showLocalCovers" class="flex items-center justify-center">
|
||||||
@ -44,19 +47,19 @@
|
|||||||
<form @submit.prevent="submitSearchForm">
|
<form @submit.prevent="submitSearchForm">
|
||||||
<div class="flex items-center justify-start -mx-1 h-20">
|
<div class="flex items-center justify-start -mx-1 h-20">
|
||||||
<div class="w-40 px-1">
|
<div class="w-40 px-1">
|
||||||
<ui-dropdown v-model="provider" :items="providers" label="Provider" small />
|
<ui-dropdown v-model="provider" :items="providers" :label="$strings.LabelProvider" small />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-72 px-1">
|
<div class="w-72 px-1">
|
||||||
<ui-text-input-with-label v-model="searchTitle" :label="searchTitleLabel" placeholder="Search" />
|
<ui-text-input-with-label v-model="searchTitle" :label="searchTitleLabel" :placeholder="$strings.PlaceholderSearch" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="provider != 'itunes'" class="w-72 px-1">
|
<div v-show="provider != 'itunes'" class="w-72 px-1">
|
||||||
<ui-text-input-with-label v-model="searchAuthor" label="Author" />
|
<ui-text-input-with-label v-model="searchAuthor" :label="$strings.LabelAuthor" />
|
||||||
</div>
|
</div>
|
||||||
<ui-btn class="mt-5 ml-1" type="submit">Search</ui-btn>
|
<ui-btn class="mt-5 ml-1" type="submit">{{ $strings.ButtonSearch }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-80 overflow-y-scroll mt-2 max-w-full">
|
<div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-80 overflow-y-scroll mt-2 max-w-full">
|
||||||
<p v-if="!coversFound.length">No Covers Found</p>
|
<p v-if="!coversFound.length">{{ $strings.MessageNoCoversFound }}</p>
|
||||||
<template v-for="cover in coversFound">
|
<template v-for="cover in coversFound">
|
||||||
<div :key="cover" class="m-0.5 mb-5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === imageUrl ? 'border-yellow-300' : ''" @click="updateCover(cover)">
|
<div :key="cover" class="m-0.5 mb-5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === imageUrl ? 'border-yellow-300' : ''" @click="updateCover(cover)">
|
||||||
<covers-preview-cover :src="cover" :width="80" show-open-new-tab :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
<covers-preview-cover :src="cover" :width="80" show-open-new-tab :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||||
@ -65,14 +68,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="previewUpload" class="absolute top-0 left-0 w-full h-full z-10 bg-bg p-8">
|
<div v-if="previewUpload" class="absolute top-0 left-0 w-full h-full z-10 bg-bg p-8">
|
||||||
<p class="text-lg">Preview Cover</p>
|
<p class="text-lg">{{ $strings.HeaderPreviewCover }}</p>
|
||||||
<span class="absolute top-4 right-4 material-icons text-2xl cursor-pointer" @click="resetCoverPreview">close</span>
|
<span class="absolute top-4 right-4 material-icons text-2xl cursor-pointer" @click="resetCoverPreview">close</span>
|
||||||
<div class="flex justify-center py-4">
|
<div class="flex justify-center py-4">
|
||||||
<covers-preview-cover :src="previewUpload" :width="240" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
<covers-preview-cover :src="previewUpload" :width="240" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute bottom-0 right-0 flex py-4 px-5">
|
<div class="absolute bottom-0 right-0 flex py-4 px-5">
|
||||||
<ui-btn :disabled="processingUpload" class="mx-2" @click="resetCoverPreview">Clear</ui-btn>
|
<ui-btn :disabled="processingUpload" class="mx-2" @click="resetCoverPreview">{{ $strings.ButtonReset }}</ui-btn>
|
||||||
<ui-btn :loading="processingUpload" color="success" @click="submitCoverUpload">Upload</ui-btn>
|
<ui-btn :loading="processingUpload" color="success" @click="submitCoverUpload">{{ $strings.ButtonUpload }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -125,9 +128,9 @@ export default {
|
|||||||
return this.$store.state.scanners.providers
|
return this.$store.state.scanners.providers
|
||||||
},
|
},
|
||||||
searchTitleLabel() {
|
searchTitleLabel() {
|
||||||
if (this.provider.startsWith('audible')) return 'Search Title or ASIN'
|
if (this.provider.startsWith('audible')) return this.$strings.LabelSearchTitleOrASIN
|
||||||
else if (this.provider == 'itunes') return 'Search Term'
|
else if (this.provider == 'itunes') return this.$strings.LabelSearchTerm
|
||||||
return 'Search Title'
|
return this.$strings.LabelSearchTitle
|
||||||
},
|
},
|
||||||
bookCoverAspectRatio() {
|
bookCoverAspectRatio() {
|
||||||
return this.$store.getters['libraries/getBookCoverAspectRatio']
|
return this.$store.getters['libraries/getBookCoverAspectRatio']
|
||||||
|
@ -7,22 +7,24 @@
|
|||||||
|
|
||||||
<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">Remove</ui-btn>
|
<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" />
|
<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" />
|
<div class="flex-grow" />
|
||||||
|
|
||||||
<ui-tooltip :disabled="!!quickMatching" :text="`Populate empty ${mediaType} details & cover with first ${mediaType} result from '${libraryProvider}'. Does not overwrite details unless 'Prefer matched metadata' server setting is enabled.`" 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">Quick Match</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>
|
||||||
|
|
||||||
<ui-tooltip :disabled="!!libraryScan" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4">
|
<ui-tooltip :disabled="!!libraryScan" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4">
|
||||||
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="!!libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">Re-Scan</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>
|
||||||
|
|
||||||
<ui-btn @click="save" class="mx-2 hidden md:block">Save</ui-btn>
|
<!-- desktop -->
|
||||||
|
<ui-btn @click="save" class="mx-2 hidden md:block">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
<ui-btn @click="saveAndClose">Save<span class="hidden md:inline-block"> & Close</span></ui-btn>
|
<ui-btn @click="saveAndClose" class="mx-2 hidden md:block">{{ $strings.ButtonSaveAndClose }}</ui-btn>
|
||||||
|
<!-- mobile -->
|
||||||
|
<ui-btn @click="saveAndClose" class="mx-2 md:hidden">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,22 +3,22 @@
|
|||||||
<form @submit.prevent="submitSearch">
|
<form @submit.prevent="submitSearch">
|
||||||
<div class="flex flex-wrap md:flex-nowrap items-center justify-start -mx-1">
|
<div class="flex flex-wrap md:flex-nowrap items-center justify-start -mx-1">
|
||||||
<div class="w-36 px-1">
|
<div class="w-36 px-1">
|
||||||
<ui-dropdown v-model="provider" :items="providers" label="Provider" small />
|
<ui-dropdown v-model="provider" :items="providers" :label="$strings.LabelProvider" small />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow md:w-72 px-1">
|
<div class="flex-grow md:w-72 px-1">
|
||||||
<ui-text-input-with-label v-model="searchTitle" :label="searchTitleLabel" placeholder="Search" />
|
<ui-text-input-with-label v-model="searchTitle" :label="searchTitleLabel" :placeholder="$strings.PlaceholderSearch" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="provider != 'itunes'" class="w-60 md:w-72 px-1">
|
<div v-show="provider != 'itunes'" class="w-60 md:w-72 px-1">
|
||||||
<ui-text-input-with-label v-model="searchAuthor" label="Author" />
|
<ui-text-input-with-label v-model="searchAuthor" :label="$strings.LabelAuthor" />
|
||||||
</div>
|
</div>
|
||||||
<ui-btn class="mt-5 ml-1" type="submit">Search</ui-btn>
|
<ui-btn class="mt-5 ml-1" type="submit">{{ $strings.ButtonSearch }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div v-show="processing" class="flex h-full items-center justify-center">
|
<div v-show="processing" class="flex h-full items-center justify-center">
|
||||||
<p>Loading...</p>
|
<p>{{ $strings.MessageLoading }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!processing && !searchResults.length && hasSearched" class="flex h-full items-center justify-center">
|
<div v-show="!processing && !searchResults.length && hasSearched" class="flex h-full items-center justify-center">
|
||||||
<p>No Results</p>
|
<p>{{ $strings.MessageNoResults }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!processing" class="w-full max-h-full overflow-y-auto overflow-x-hidden matchListWrapper mt-4">
|
<div v-show="!processing" class="w-full max-h-full overflow-y-auto overflow-x-hidden matchListWrapper mt-4">
|
||||||
<template v-for="(res, index) in searchResults">
|
<template v-for="(res, index) in searchResults">
|
||||||
@ -30,13 +30,13 @@
|
|||||||
<div class="w-8 h-8 rounded-full hover:bg-white hover:bg-opacity-10 flex items-center justify-center cursor-pointer" @click="clearSelectedMatch">
|
<div class="w-8 h-8 rounded-full hover:bg-white hover:bg-opacity-10 flex items-center justify-center cursor-pointer" @click="clearSelectedMatch">
|
||||||
<span class="material-icons text-3xl">arrow_back</span>
|
<span class="material-icons text-3xl">arrow_back</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xl pl-3">Update Book Details</p>
|
<p class="text-xl pl-3">{{ $strings.HeaderUpdateDetails }}</p>
|
||||||
</div>
|
</div>
|
||||||
<ui-checkbox v-model="selectAll" checkbox-bg="bg" @input="selectAllToggled" />
|
<ui-checkbox v-model="selectAll" checkbox-bg="bg" @input="selectAllToggled" />
|
||||||
<form @submit.prevent="submitMatchUpdate">
|
<form @submit.prevent="submitMatchUpdate">
|
||||||
<div v-if="selectedMatchOrig.cover" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.cover" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.cover" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.cover" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<ui-text-input-with-label v-model="selectedMatch.cover" :disabled="!selectedMatchUsage.cover" readonly label="Cover" class="flex-grow mx-4" />
|
<ui-text-input-with-label v-model="selectedMatch.cover" :disabled="!selectedMatchUsage.cover" readonly :label="$strings.LabelCover" class="flex-grow mx-4" />
|
||||||
<div class="min-w-12 max-w-12 md:min-w-16 md:max-w-16">
|
<div class="min-w-12 max-w-12 md:min-w-16 md:max-w-16">
|
||||||
<a :href="selectedMatch.cover" target="_blank" class="w-full bg-primary">
|
<a :href="selectedMatch.cover" target="_blank" class="w-full bg-primary">
|
||||||
<img :src="selectedMatch.cover" class="h-full w-full object-contain" />
|
<img :src="selectedMatch.cover" class="h-full w-full object-contain" />
|
||||||
@ -46,50 +46,50 @@
|
|||||||
<div v-if="selectedMatchOrig.title" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.title" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.title" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.title" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.title" :disabled="!selectedMatchUsage.title" label="Title" />
|
<ui-text-input-with-label v-model="selectedMatch.title" :disabled="!selectedMatchUsage.title" :label="$strings.LabelTitle" />
|
||||||
<p v-if="mediaMetadata.title" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.title || '' }}</p>
|
<p v-if="mediaMetadata.title" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.title || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.subtitle" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.subtitle" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.subtitle" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.subtitle" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.subtitle" :disabled="!selectedMatchUsage.subtitle" label="Subtitle" />
|
<ui-text-input-with-label v-model="selectedMatch.subtitle" :disabled="!selectedMatchUsage.subtitle" :label="$strings.LabelSubtitle" />
|
||||||
<p v-if="mediaMetadata.subtitle" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.subtitle || '' }}</p>
|
<p v-if="mediaMetadata.subtitle" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.subtitle || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.author" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.author" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.author" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.author" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.author" :disabled="!selectedMatchUsage.author" label="Author" />
|
<ui-text-input-with-label v-model="selectedMatch.author" :disabled="!selectedMatchUsage.author" :label="$strings.LabelAuthor" />
|
||||||
<p v-if="mediaMetadata.authorName" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.authorName || '' }}</p>
|
<p v-if="mediaMetadata.authorName" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.authorName || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.narrator" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.narrator" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.narrator" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.narrator" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.narrator" :disabled="!selectedMatchUsage.narrator" label="Narrator" />
|
<ui-text-input-with-label v-model="selectedMatch.narrator" :disabled="!selectedMatchUsage.narrator" :label="$strings.LabelNarrators" />
|
||||||
<p v-if="mediaMetadata.narratorName" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.narratorName || '' }}</p>
|
<p v-if="mediaMetadata.narratorName" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.narratorName || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.description" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.description" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.description" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.description" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-textarea-with-label v-model="selectedMatch.description" :rows="3" :disabled="!selectedMatchUsage.description" label="Description" />
|
<ui-textarea-with-label v-model="selectedMatch.description" :rows="3" :disabled="!selectedMatchUsage.description" :label="$strings.LabelDescription" />
|
||||||
<p v-if="mediaMetadata.description" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.description.substr(0, 100) + (mediaMetadata.description.length > 100 ? '...' : '') }}</p>
|
<p v-if="mediaMetadata.description" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.description.substr(0, 100) + (mediaMetadata.description.length > 100 ? '...' : '') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.publisher" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.publisher" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.publisher" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.publisher" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.publisher" :disabled="!selectedMatchUsage.publisher" label="Publisher" />
|
<ui-text-input-with-label v-model="selectedMatch.publisher" :disabled="!selectedMatchUsage.publisher" :label="$strings.LabelPublisher" />
|
||||||
<p v-if="mediaMetadata.publisher" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.publisher || '' }}</p>
|
<p v-if="mediaMetadata.publisher" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.publisher || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.publishedYear" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.publishedYear" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.publishedYear" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.publishedYear" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.publishedYear" :disabled="!selectedMatchUsage.publishedYear" label="Published Year" />
|
<ui-text-input-with-label v-model="selectedMatch.publishedYear" :disabled="!selectedMatchUsage.publishedYear" :label="$strings.LabelPublishYear" />
|
||||||
<p v-if="mediaMetadata.publishedYear" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.publishedYear || '' }}</p>
|
<p v-if="mediaMetadata.publishedYear" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.publishedYear || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -97,42 +97,42 @@
|
|||||||
<ui-checkbox v-model="selectedMatchUsage.series" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.series" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<widgets-series-input-widget v-model="selectedMatch.series" :disabled="!selectedMatchUsage.series" />
|
<widgets-series-input-widget v-model="selectedMatch.series" :disabled="!selectedMatchUsage.series" />
|
||||||
<p v-if="mediaMetadata.seriesName" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.seriesName || '' }}</p>
|
<p v-if="mediaMetadata.seriesName" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.seriesName || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.genres && selectedMatchOrig.genres.length" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.genres && selectedMatchOrig.genres.length" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.genres" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.genres" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-multi-select v-model="selectedMatch.genres" :items="selectedMatch.genres" :disabled="!selectedMatchUsage.genres" label="Genres" />
|
<ui-multi-select v-model="selectedMatch.genres" :items="selectedMatch.genres" :disabled="!selectedMatchUsage.genres" :label="$strings.LabelGenres" />
|
||||||
<p v-if="mediaMetadata.genres" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.genres.join(', ') }}</p>
|
<p v-if="mediaMetadata.genres" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.genres.join(', ') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.tags" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.tags" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.tags" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.tags" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.tags" :disabled="!selectedMatchUsage.tags" label="Tags" />
|
<ui-text-input-with-label v-model="selectedMatch.tags" :disabled="!selectedMatchUsage.tags" :label="$strings.LabelTags" />
|
||||||
<p v-if="media.tags" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ media.tags.join(', ') }}</p>
|
<p v-if="media.tags" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ media.tags.join(', ') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.language" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.language" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.language" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.language" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.language" :disabled="!selectedMatchUsage.language" label="Language" />
|
<ui-text-input-with-label v-model="selectedMatch.language" :disabled="!selectedMatchUsage.language" :label="$strings.LabelLanguage" />
|
||||||
<p v-if="mediaMetadata.language" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.language || '' }}</p>
|
<p v-if="mediaMetadata.language" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.language || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.isbn" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.isbn" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.isbn" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.isbn" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" />
|
<ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" />
|
||||||
<p v-if="mediaMetadata.isbn" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.isbn || '' }}</p>
|
<p v-if="mediaMetadata.isbn" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.isbn || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.asin" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.asin" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.asin" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.asin" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.asin" :disabled="!selectedMatchUsage.asin" label="ASIN" />
|
<ui-text-input-with-label v-model="selectedMatch.asin" :disabled="!selectedMatchUsage.asin" label="ASIN" />
|
||||||
<p v-if="mediaMetadata.asin" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.asin || '' }}</p>
|
<p v-if="mediaMetadata.asin" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.asin || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -140,33 +140,33 @@
|
|||||||
<ui-checkbox v-model="selectedMatchUsage.itunesId" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.itunesId" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.itunesId" type="number" :disabled="!selectedMatchUsage.itunesId" label="iTunes ID" />
|
<ui-text-input-with-label v-model="selectedMatch.itunesId" type="number" :disabled="!selectedMatchUsage.itunesId" label="iTunes ID" />
|
||||||
<p v-if="mediaMetadata.itunesId" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.itunesId || '' }}</p>
|
<p v-if="mediaMetadata.itunesId" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.itunesId || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.feedUrl" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.feedUrl" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.feedUrl" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.feedUrl" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.feedUrl" :disabled="!selectedMatchUsage.feedUrl" label="RSS Feed URL" />
|
<ui-text-input-with-label v-model="selectedMatch.feedUrl" :disabled="!selectedMatchUsage.feedUrl" label="RSS Feed URL" />
|
||||||
<p v-if="mediaMetadata.feedUrl" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.feedUrl || '' }}</p>
|
<p v-if="mediaMetadata.feedUrl" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.feedUrl || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.itunesPageUrl" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.itunesPageUrl" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.itunesPageUrl" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.itunesPageUrl" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.itunesPageUrl" :disabled="!selectedMatchUsage.itunesPageUrl" label="iTunes Page URL" />
|
<ui-text-input-with-label v-model="selectedMatch.itunesPageUrl" :disabled="!selectedMatchUsage.itunesPageUrl" label="iTunes Page URL" />
|
||||||
<p v-if="mediaMetadata.itunesPageUrl" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.itunesPageUrl || '' }}</p>
|
<p v-if="mediaMetadata.itunesPageUrl" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.itunesPageUrl || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedMatchOrig.releaseDate" class="flex items-center py-2">
|
<div v-if="selectedMatchOrig.releaseDate" class="flex items-center py-2">
|
||||||
<ui-checkbox v-model="selectedMatchUsage.releaseDate" checkbox-bg="bg" @input="checkboxToggled" />
|
<ui-checkbox v-model="selectedMatchUsage.releaseDate" checkbox-bg="bg" @input="checkboxToggled" />
|
||||||
<div class="flex-grow ml-4">
|
<div class="flex-grow ml-4">
|
||||||
<ui-text-input-with-label v-model="selectedMatch.releaseDate" :disabled="!selectedMatchUsage.releaseDate" label="Release Date" />
|
<ui-text-input-with-label v-model="selectedMatch.releaseDate" :disabled="!selectedMatchUsage.releaseDate" :label="$strings.LabelReleaseDate" />
|
||||||
<p v-if="mediaMetadata.releaseDate" class="text-xs ml-1 text-white text-opacity-60">Currently: {{ mediaMetadata.releaseDate || '' }}</p>
|
<p v-if="mediaMetadata.releaseDate" class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelCurrently }} {{ mediaMetadata.releaseDate || '' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end py-2">
|
<div class="flex items-center justify-end py-2">
|
||||||
<ui-btn color="success" type="submit">Update</ui-btn>
|
<ui-btn color="success" type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -258,9 +258,9 @@ export default {
|
|||||||
return this.$store.state.scanners.providers
|
return this.$store.state.scanners.providers
|
||||||
},
|
},
|
||||||
searchTitleLabel() {
|
searchTitleLabel() {
|
||||||
if (this.provider.startsWith('audible')) return 'Search Title or ASIN'
|
if (this.provider.startsWith('audible')) return this.$strings.LabelSearchTitleOrASIN
|
||||||
else if (this.provider == 'itunes') return 'Search Term'
|
else if (this.provider == 'itunes') return this.$strings.LabelSearchTerm
|
||||||
return 'Search Title'
|
return this.$strings.LabelSearchTitle
|
||||||
},
|
},
|
||||||
media() {
|
media() {
|
||||||
return this.libraryItem ? this.libraryItem.media || {} : {}
|
return this.libraryItem ? this.libraryItem.media || {} : {}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full overflow-hidden overflow-y-auto px-4 py-6">
|
<div class="w-full h-full overflow-hidden overflow-y-auto px-4 py-6">
|
||||||
<p class="text-xl font-semibold mb-2">Audiobook File Management Tools</p>
|
<p class="text-xl font-semibold mb-2">{{ $strings.HeaderAudiobookTools }}</p>
|
||||||
|
|
||||||
<!-- Merge to m4b -->
|
<!-- Merge to m4b -->
|
||||||
<div v-if="showM4bDownload" class="w-full border border-black-200 p-4 my-8">
|
<div v-if="showM4bDownload" class="w-full border border-black-200 p-4 my-8">
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<div>
|
<div>
|
||||||
<ui-btn :to="`/audiobook/${libraryItemId}/manage?tool=m4b`" class="flex items-center"
|
<ui-btn :to="`/audiobook/${libraryItemId}/manage?tool=m4b`" class="flex items-center"
|
||||||
>Open Manager
|
>{{ $strings.ButtonOpenManager }}
|
||||||
<span class="material-icons text-lg ml-2">launch</span>
|
<span class="material-icons text-lg ml-2">launch</span>
|
||||||
</ui-btn>
|
</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<div>
|
<div>
|
||||||
<ui-btn :to="`/audiobook/${libraryItemId}/manage?tool=embed`" class="flex items-center"
|
<ui-btn :to="`/audiobook/${libraryItemId}/manage?tool=embed`" class="flex items-center"
|
||||||
>Open Manager
|
>{{ $strings.ButtonOpenManager }}
|
||||||
<span class="material-icons text-lg ml-2">launch</span>
|
<span class="material-icons text-lg ml-2">launch</span>
|
||||||
</ui-btn>
|
</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
<div v-if="!showDirectoryPicker" class="w-full h-full py-4">
|
<div v-if="!showDirectoryPicker" class="w-full h-full py-4">
|
||||||
<div class="flex flex-wrap md:flex-nowrap -mx-1">
|
<div class="flex flex-wrap md:flex-nowrap -mx-1">
|
||||||
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
||||||
<ui-dropdown v-model="mediaType" :items="mediaTypes" label="Media Type" :disabled="!isNew" small @input="changedMediaType" />
|
<ui-dropdown v-model="mediaType" :items="mediaTypes" :label="$strings.LabelMediaType" :disabled="!isNew" small @input="changedMediaType" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full md:flex-grow px-1 py-1 md:py-0">
|
<div class="w-full md:flex-grow px-1 py-1 md:py-0">
|
||||||
<ui-text-input-with-label v-model="name" label="Library Name" @blur="nameBlurred" />
|
<ui-text-input-with-label v-model="name" :label="$strings.LabelLibraryName" @blur="nameBlurred" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/5 md:w-18 px-1 py-1 md:py-0">
|
<div class="w-1/5 md:w-18 px-1 py-1 md:py-0">
|
||||||
<ui-media-icon-picker v-model="icon" @input="iconChanged" />
|
<ui-media-icon-picker v-model="icon" :label="$strings.LabelIcon" @input="iconChanged" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
||||||
<ui-dropdown v-model="provider" :items="providers" label="Metadata Provider" small @input="formUpdated" />
|
<ui-dropdown v-model="provider" :items="providers" :label="$strings.LabelMetadataProvider" small @input="formUpdated" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full py-4">
|
<div class="w-full py-4">
|
||||||
<p class="px-1 text-sm font-semibold">Folders</p>
|
<p class="px-1 text-sm font-semibold">{{ $strings.LabelFolders }}</p>
|
||||||
<div v-for="(folder, index) in folders" :key="index" class="w-full flex items-center py-1 px-2">
|
<div v-for="(folder, index) in folders" :key="index" class="w-full flex items-center py-1 px-2">
|
||||||
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
|
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
|
||||||
<ui-editable-text v-model="folder.fullPath" readonly type="text" class="w-full" />
|
<ui-editable-text v-model="folder.fullPath" readonly type="text" class="w-full" />
|
||||||
@ -25,10 +25,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex py-1 px-2 items-center w-full">
|
<div class="flex py-1 px-2 items-center w-full">
|
||||||
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
|
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
|
||||||
<ui-editable-text v-model="newFolderPath" placeholder="New folder path" type="text" class="w-full" @blur="newFolderInputBlurred" />
|
<ui-editable-text v-model="newFolderPath" :placeholder="$strings.PlaceholderNewFolderPath" type="text" class="w-full" @blur="newFolderInputBlurred" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ui-btn class="w-full mt-2" color="primary" @click="browseForFolder">Browse for Folder</ui-btn>
|
<ui-btn class="w-full mt-2" color="primary" @click="browseForFolder">{{ $strings.ButtonBrowseForFolder }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<modals-libraries-folder-chooser v-else :paths="folderPaths" @back="showDirectoryPicker = false" @select="selectFolder" />
|
<modals-libraries-folder-chooser v-else :paths="folderPaths" @back="showDirectoryPicker = false" @select="selectFolder" />
|
||||||
|
@ -36,23 +36,6 @@ export default {
|
|||||||
return {
|
return {
|
||||||
processing: false,
|
processing: false,
|
||||||
selectedTab: 'details',
|
selectedTab: 'details',
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
id: 'details',
|
|
||||||
title: 'Details',
|
|
||||||
component: 'modals-libraries-edit-library'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'settings',
|
|
||||||
title: 'Settings',
|
|
||||||
component: 'modals-libraries-library-settings'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'schedule',
|
|
||||||
title: 'Schedule',
|
|
||||||
component: 'modals-libraries-schedule-scan'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
libraryCopy: null
|
libraryCopy: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -66,10 +49,29 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return this.library ? 'Update Library' : 'New Library'
|
return this.library ? this.$strings.HeaderUpdateLibrary : this.$strings.HeaderNewLibrary
|
||||||
},
|
},
|
||||||
buttonText() {
|
buttonText() {
|
||||||
return this.library ? 'Update Library' : 'Create New Library'
|
return this.library ? this.$strings.ButtonSave : this.$strings.ButtonCreate
|
||||||
|
},
|
||||||
|
tabs() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'details',
|
||||||
|
title: this.$strings.HeaderDetails,
|
||||||
|
component: 'modals-libraries-edit-library'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'settings',
|
||||||
|
title: this.$strings.HeaderSettings,
|
||||||
|
component: 'modals-libraries-library-settings'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'schedule',
|
||||||
|
title: this.$strings.HeaderSchedule,
|
||||||
|
component: 'modals-libraries-schedule-scan'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
tabName() {
|
tabName() {
|
||||||
var _tab = this.tabs.find((t) => t.id === this.selectedTab)
|
var _tab = this.tabs.find((t) => t.id === this.selectedTab)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="w-full h-full bg-bg absolute top-0 left-0 px-4 py-4 z-10">
|
<div class="w-full h-full bg-bg absolute top-0 left-0 px-4 py-4 z-10">
|
||||||
<div class="flex items-center py-1 mb-2">
|
<div class="flex items-center py-1 mb-2">
|
||||||
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="$emit('back')">arrow_back</span>
|
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="$emit('back')">arrow_back</span>
|
||||||
<p class="px-4 text-xl">Choose a Folder</p>
|
<p class="px-4 text-xl">{{ $strings.HeaderChooseAFolder }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="allFolders.length" class="w-full bg-primary bg-opacity-70 py-1 px-4 mb-2">
|
<div v-if="allFolders.length" class="w-full bg-primary bg-opacity-70 py-1 px-4 mb-2">
|
||||||
<p class="font-mono truncate">{{ selectedPath || '\\' }}</p>
|
<p class="font-mono truncate">{{ selectedPath || '\\' }}</p>
|
||||||
@ -27,16 +27,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="loadingFolders" class="py-12 text-center">
|
<div v-else-if="loadingFolders" class="py-12 text-center">
|
||||||
<p>Loading folders...</p>
|
<p>{{ $strings.MessageLoadingFolders }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="py-12 text-center max-w-sm mx-auto">
|
<div v-else class="py-12 text-center max-w-sm mx-auto">
|
||||||
<p class="text-lg mb-2">No Folders Available</p>
|
<p class="text-lg mb-2">{{ $strings.MessageNoFoldersAvailable }}</p>
|
||||||
<p class="text-gray-300 mb-2">Note: folders already mapped will not be shown</p>
|
<p class="text-gray-300 mb-2">{{ $strings.NoteFolderPicker }}</p>
|
||||||
<p v-if="isDebian" class="text-red-400">Note: Folder picker for the debian install is not fully implemented. You should enter the path to your library directly.</p>
|
<p v-if="isDebian" class="text-red-400">{{ $strings.NoteFolderPickerDebian }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full py-2">
|
<div class="w-full py-2">
|
||||||
<ui-btn :disabled="!selectedPath" color="primary" class="w-full mt-2" @click="selectFolder">Select Folder Path</ui-btn>
|
<ui-btn :disabled="!selectedPath" color="primary" class="w-full mt-2" @click="selectFolder">{{ $strings.ButtonSelectFolderPath }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="useSquareBookCovers" @input="formUpdated" />
|
<ui-toggle-switch v-model="useSquareBookCovers" @input="formUpdated" />
|
||||||
<ui-tooltip :text="tooltips.coverAspectRatio">
|
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
|
||||||
<p class="pl-4 text-base">
|
<p class="pl-4 text-base">
|
||||||
Use square book covers
|
{{ $strings.LabelSettingsSquareBookCovers }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -13,20 +13,20 @@
|
|||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="disableWatcher" @input="formUpdated" />
|
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="disableWatcher" @input="formUpdated" />
|
||||||
<ui-toggle-switch v-else disabled :value="false" />
|
<ui-toggle-switch v-else disabled :value="false" />
|
||||||
<p class="pl-4 text-base">Disable folder watcher for library</p>
|
<p class="pl-4 text-base">{{ $strings.LabelSettingsDisableWatcherForLibrary }}</p>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*Watcher is disabled globally in server settings</p>
|
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="mediaType == 'book'" class="py-3">
|
<div v-if="mediaType == 'book'" class="py-3">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" @input="formUpdated" />
|
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" @input="formUpdated" />
|
||||||
<p class="pl-4 text-base">Skip matching books that already have an ASIN</p>
|
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="mediaType == 'book'" class="py-3">
|
<div v-if="mediaType == 'book'" class="py-3">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ui-toggle-switch v-model="skipMatchingMediaWithIsbn" @input="formUpdated" />
|
<ui-toggle-switch v-model="skipMatchingMediaWithIsbn" @input="formUpdated" />
|
||||||
<p class="pl-4 text-base">Skip matching books that already have an ISBN</p>
|
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithISBN }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -47,10 +47,7 @@ export default {
|
|||||||
useSquareBookCovers: false,
|
useSquareBookCovers: false,
|
||||||
disableWatcher: false,
|
disableWatcher: false,
|
||||||
skipMatchingMediaWithAsin: false,
|
skipMatchingMediaWithAsin: false,
|
||||||
skipMatchingMediaWithIsbn: false,
|
skipMatchingMediaWithIsbn: false
|
||||||
tooltips: {
|
|
||||||
coverAspectRatio: 'Prefer to use square covers over standard 1.6:1 book covers'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<p class="text-base md:text-xl font-semibold">Schedule Automatic Library Scans</p>
|
<p class="text-base md:text-xl font-semibold">{{ $strings.HeaderScheduleLibraryScans }}</p>
|
||||||
<ui-checkbox v-model="enableAutoScan" @input="toggleEnableAutoScan" label="Enable" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" />
|
<ui-checkbox v-model="enableAutoScan" @input="toggleEnableAutoScan" :label="$strings.LabelEnable" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" />
|
||||||
</div>
|
</div>
|
||||||
<widgets-cron-expression-builder ref="cronExpressionBuilder" v-if="enableAutoScan" v-model="cronExpression" @input="updatedCron" />
|
<widgets-cron-expression-builder ref="cronExpressionBuilder" v-if="enableAutoScan" v-model="cronExpression" @input="updatedCron" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,23 +8,25 @@
|
|||||||
<form @submit.prevent="submitForm">
|
<form @submit.prevent="submitForm">
|
||||||
<div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300">
|
<div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
<div class="w-full px-3 py-5 md:p-12">
|
<div class="w-full px-3 py-5 md:p-12">
|
||||||
<ui-dropdown v-model="newNotification.eventName" label="Notification Event" :items="eventOptions" class="mb-4" @input="eventOptionUpdated" />
|
<ui-dropdown v-model="newNotification.eventName" :label="$strings.LabelNotificationEvent" :items="eventOptions" class="mb-4" @input="eventOptionUpdated" />
|
||||||
|
|
||||||
<ui-multi-select v-model="newNotification.urls" label="Apprise URL(s)" class="mb-2" />
|
<ui-multi-select v-model="newNotification.urls" :label="$strings.LabelNotificationAppriseURL" class="mb-2" />
|
||||||
|
|
||||||
<ui-text-input-with-label v-model="newNotification.titleTemplate" label="Title Template" class="mb-2" />
|
<ui-text-input-with-label v-model="newNotification.titleTemplate" :label="$strings.LabelNotificationTitleTemplate" class="mb-2" />
|
||||||
|
|
||||||
<ui-textarea-with-label v-model="newNotification.bodyTemplate" label="Body Template" :rows="4" class="mb-2" />
|
<ui-textarea-with-label v-model="newNotification.bodyTemplate" :label="$strings.LabelNotificationBodyTemplate" :rows="4" class="mb-2" />
|
||||||
|
|
||||||
<p v-if="availableVariables" class="text-sm text-gray-300"><strong>Available variables:</strong> {{ availableVariables.join(', ') }}</p>
|
<p v-if="availableVariables" class="text-sm text-gray-300">
|
||||||
|
<strong>{{ $strings.LabelNotificationAvailableVariables }}:</strong> {{ availableVariables.join(', ') }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="flex items-center pt-4">
|
<div class="flex items-center pt-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ui-toggle-switch v-model="newNotification.enabled" />
|
<ui-toggle-switch v-model="newNotification.enabled" />
|
||||||
<p class="text-lg pl-2">Enabled</p>
|
<p class="text-lg pl-2">{{ $strings.LabelEnable }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn color="success" type="submit">Submit</ui-btn>
|
<ui-btn color="success" type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
<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-8 mt-2 px-1" v-html="message" />
|
||||||
<div class="flex px-1 items-center">
|
<div class="flex px-1 items-center">
|
||||||
<ui-btn v-if="isYesNo" color="primary" @click="nevermind">Cancel</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">Yes</ui-btn>
|
<ui-btn v-if="isYesNo" color="success" @click="confirm">{{ $strings.ButtonYes }}</ui-btn>
|
||||||
<ui-btn v-else color="primary" @click="confirm">Ok</ui-btn>
|
<ui-btn v-else color="primary" @click="confirm">{{ $strings.ButtonOk }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-96 my-6 mx-auto">
|
<div class="w-96 my-6 mx-auto">
|
||||||
<h1 class="text-2xl mb-4 font-book">Minutes Listening <span class="text-white text-opacity-60 text-lg">(Last 7 days)</span></h1>
|
<h1 class="text-2xl mb-4 font-book">{{ $strings.HeaderStatsMinutesListeningChart }}</h1>
|
||||||
<div class="relative w-96 h-72">
|
<div class="relative w-96 h-72">
|
||||||
<div class="absolute top-0 left-0">
|
<div class="absolute top-0 left-0">
|
||||||
<template v-for="lbl in yAxisLabels">
|
<template v-for="lbl in yAxisLabels">
|
||||||
@ -34,24 +34,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between pt-12">
|
<div class="flex justify-between pt-12">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">Week Listening</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ totalMinutesListeningThisWeek }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ totalMinutesListeningThisWeek }}</p>
|
||||||
<p class="text-sm text-center">minutes</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">Daily Average</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ averageMinutesPerDay }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ averageMinutesPerDay }}</p>
|
||||||
<p class="text-sm text-center">minutes</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">Best Day</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ mostListenedDay }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ mostListenedDay }}</p>
|
||||||
<p class="text-sm text-center">minutes</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">Days</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ daysInARow }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ daysInARow }}</p>
|
||||||
<p class="text-sm text-center">in a row</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalItems }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalItems }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Items in Library</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsItemsInLibrary }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<span class="material-icons text-7xl">show_chart</span>
|
<span class="material-icons text-7xl">show_chart</span>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalTime }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalTime }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Overall {{ useOverallHours ? 'Hours' : 'Days' }}</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsOverall }} {{ useOverallHours ? $strings.LabelStatsHours : $strings.LabelStatsDays }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalAuthors }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalAuthors }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Authors</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsAuthors }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<span class="material-icons-outlined text-6xl pt-1">insert_drive_file</span>
|
<span class="material-icons-outlined text-6xl pt-1">insert_drive_file</span>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalSizeNum }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalSizeNum }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Size ({{ totalSizeMod }})</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelSize }} ({{ totalSizeMod }})</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<span class="material-icons-outlined text-6xl pt-1">audio_file</span>
|
<span class="material-icons-outlined text-6xl pt-1">audio_file</span>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ numAudioTracks }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ numAudioTracks }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Audio Tracks</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsAudioTracks }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-center mt-4">
|
<div class="text-center mt-4">
|
||||||
<div class="flex py-4">
|
<div class="flex py-4">
|
||||||
<ui-file-input ref="fileInput" class="mr-2" accept=".audiobookshelf" @change="backupUploaded">Upload Backup</ui-file-input>
|
<ui-file-input ref="fileInput" class="mr-2" accept=".audiobookshelf" @change="backupUploaded">{{ $strings.ButtonUploadBackup }}</ui-file-input>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn :loading="isBackingUp" @click="clickCreateBackup">Create Backup</ui-btn>
|
<ui-btn :loading="isBackingUp" @click="clickCreateBackup">{{ $strings.ButtonCreateBackup }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<table id="backups">
|
<table id="backups">
|
||||||
<tr>
|
<tr>
|
||||||
<th>File</th>
|
<th>{{ $strings.LabelFile }}</th>
|
||||||
<th class="hidden sm:table-cell w-32 md:w-56">Datetime</th>
|
<th class="hidden sm:table-cell w-32 md:w-56">{{ $strings.LabelDatetime }}</th>
|
||||||
<th class="hidden sm:table-cell w-20 md:w-28">Size</th>
|
<th class="hidden sm:table-cell w-20 md:w-28">{{ $strings.LabelSize }}</th>
|
||||||
<th class="w-36"></th>
|
<th class="w-36"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="backup in backups" :key="backup.id" :class="!backup.serverVersion ? 'bg-error bg-opacity-10' : ''">
|
<tr v-for="backup in backups" :key="backup.id" :class="!backup.serverVersion ? 'bg-error bg-opacity-10' : ''">
|
||||||
@ -21,7 +21,7 @@
|
|||||||
<td class="hidden sm:table-cell font-mono md:text-sm text-xs">{{ $bytesPretty(backup.fileSize) }}</td>
|
<td class="hidden sm:table-cell font-mono md:text-sm text-xs">{{ $bytesPretty(backup.fileSize) }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="w-full flex flex-row items-center justify-center">
|
<div class="w-full flex flex-row items-center justify-center">
|
||||||
<ui-btn v-if="backup.serverVersion" small color="primary" @click="applyBackup(backup)">Restore</ui-btn>
|
<ui-btn v-if="backup.serverVersion" small color="primary" @click="applyBackup(backup)">{{ $strings.ButtonRestore }}</ui-btn>
|
||||||
|
|
||||||
<a v-if="backup.serverVersion" :href="`/metadata/${$encodeUriPath(backup.path)}?token=${userToken}`" class="mx-1 pt-1 hover:text-opacity-100 text-opacity-70 text-white" download><span class="material-icons text-xl">download</span></a>
|
<a v-if="backup.serverVersion" :href="`/metadata/${$encodeUriPath(backup.path)}?token=${userToken}`" class="mx-1 pt-1 hover:text-opacity-100 text-opacity-70 text-white" download><span class="material-icons text-xl">download</span></a>
|
||||||
<ui-tooltip v-else text="This backup was created with an old version of audiobookshelf no longer supported" direction="bottom" class="mx-2 flex items-center">
|
<ui-tooltip v-else text="This backup was created with an old version of audiobookshelf no longer supported" direction="bottom" class="mx-2 flex items-center">
|
||||||
@ -43,16 +43,14 @@
|
|||||||
|
|
||||||
<prompt-dialog v-model="showConfirmApply" :width="675">
|
<prompt-dialog v-model="showConfirmApply" :width="675">
|
||||||
<div v-if="selectedBackup" class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
<div v-if="selectedBackup" class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
<p class="text-error text-lg font-semibold">Important Notice!</p>
|
<p class="text-error text-lg font-semibold">{{ $strings.MessageImportantNotice }}</p>
|
||||||
<p class="text-base py-1">Applying a backup will overwrite users, user progress, book details, settings, and covers stored in metadata with the backed up data.</p>
|
<p class="text-base py-1" v-html="$strings.MessageRestoreBackupWarning" />
|
||||||
<p class="text-base py-1">Backups <strong>do not</strong> modify any files in your library folders, only data in the audiobookshelf created <span class="font-mono">/config</span> and <span class="font-mono">/metadata</span> directories. If you have enabled server settings to store cover art and metadata in your library folders then those are not backed up or overwritten.</p>
|
|
||||||
<p class="text-base py-1">All clients using your server will be automatically refreshed.</p>
|
|
||||||
|
|
||||||
<p class="text-lg text-center my-8">Are you sure you want to apply the backup created on {{ selectedBackup.datePretty }}?</p>
|
<p class="text-lg text-center my-8">{{ $strings.MessageRestoreBackupConfirm }} {{ selectedBackup.datePretty }}?</p>
|
||||||
<div class="flex px-1 items-center">
|
<div class="flex px-1 items-center">
|
||||||
<ui-btn color="primary" @click="showConfirmApply = false">Nevermind</ui-btn>
|
<ui-btn color="primary" @click="showConfirmApply = false">{{ $strings.ButtonNevermind }}</ui-btn>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn color="success" @click="confirm">Apply Backup</ui-btn>
|
<ui-btn color="success" @click="confirm">{{ $strings.ButtonRestore }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</prompt-dialog>
|
</prompt-dialog>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full my-2">
|
<div class="w-full my-2">
|
||||||
<div class="w-full bg-primary px-6 py-2 flex items-center cursor-pointer" @click.stop="clickBar">
|
<div class="w-full bg-primary px-6 py-2 flex items-center cursor-pointer" @click.stop="clickBar">
|
||||||
<p class="pr-4">Chapters</p>
|
<p class="pr-4">{{ $strings.HeaderChapters }}</p>
|
||||||
<span class="bg-black-400 rounded-xl py-1 px-2 text-sm font-mono">{{ chapters.length }}</span>
|
<span class="bg-black-400 rounded-xl py-1 px-2 text-sm font-mono">{{ chapters.length }}</span>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="userCanUpdate" small :to="`/audiobook/${libraryItemId}/chapters`" color="primary" class="mr-2">Edit Chapters</ui-btn>
|
<ui-btn v-if="userCanUpdate" small :to="`/audiobook/${libraryItemId}/chapters`" color="primary" class="mr-2">{{ $strings.ButtonEditChapters }}</ui-btn>
|
||||||
<div v-if="!keepOpen" class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="expanded ? 'transform rotate-180' : ''">
|
<div v-if="!keepOpen" class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="expanded ? 'transform rotate-180' : ''">
|
||||||
<span class="material-icons text-4xl">expand_more</span>
|
<span class="material-icons text-4xl">expand_more</span>
|
||||||
</div>
|
</div>
|
||||||
@ -13,9 +13,9 @@
|
|||||||
<table class="text-sm tracksTable" v-show="expanded || keepOpen">
|
<table class="text-sm tracksTable" v-show="expanded || keepOpen">
|
||||||
<tr class="font-book">
|
<tr class="font-book">
|
||||||
<th class="text-left w-16"><span class="px-4">Id</span></th>
|
<th class="text-left w-16"><span class="px-4">Id</span></th>
|
||||||
<th class="text-left">Title</th>
|
<th class="text-left">{{ $strings.LabelTitle }}</th>
|
||||||
<th class="text-center">Start</th>
|
<th class="text-center">{{ $strings.LabelStart }}</th>
|
||||||
<th class="text-center">End</th>
|
<th class="text-center">{{ $strings.LabelEnd }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="chapter in chapters" :key="chapter.id">
|
<tr v-for="chapter in chapters" :key="chapter.id">
|
||||||
<td class="text-left">
|
<td class="text-left">
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full my-2">
|
<div class="w-full my-2">
|
||||||
<div class="w-full bg-primary px-4 md:px-6 py-2 flex items-center cursor-pointer" @click.stop="clickBar">
|
<div class="w-full bg-primary px-4 md:px-6 py-2 flex items-center cursor-pointer" @click.stop="clickBar">
|
||||||
<p class="pr-2 md:pr-4">Library Files</p>
|
<p class="pr-2 md:pr-4">{{ $strings.HeaderLibraryFiles }}</p>
|
||||||
<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">{{ files.length }}</span>
|
<span class="text-sm font-mono">{{ files.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">Full Path</ui-btn>
|
<ui-btn small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
|
||||||
<div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''">
|
<div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''">
|
||||||
<span class="material-icons text-4xl">expand_more</span>
|
<span class="material-icons text-4xl">expand_more</span>
|
||||||
</div>
|
</div>
|
||||||
@ -15,10 +15,10 @@
|
|||||||
<div class="w-full" v-show="showFiles">
|
<div class="w-full" v-show="showFiles">
|
||||||
<table class="text-sm tracksTable">
|
<table class="text-sm tracksTable">
|
||||||
<tr class="font-book">
|
<tr class="font-book">
|
||||||
<th class="text-left px-4">Path</th>
|
<th class="text-left px-4">{{ $strings.LabelPath }}</th>
|
||||||
<th class="text-left w-24 min-w-24">Size</th>
|
<th class="text-left w-24 min-w-24">{{ $strings.LabelSize }}</th>
|
||||||
<th class="text-left px-4 w-24">Filetype</th>
|
<th class="text-left px-4 w-24">{{ $strings.LabelType }}</th>
|
||||||
<th v-if="userCanDownload && !isMissing" class="text-center w-20">Download</th>
|
<th v-if="userCanDownload && !isMissing" class="text-center w-20">{{ $strings.LabelDownload }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-for="file in files">
|
<template v-for="file in files">
|
||||||
<tr :key="file.path">
|
<tr :key="file.path">
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
<div class="w-full" v-show="expand">
|
<div class="w-full" v-show="expand">
|
||||||
<table class="text-sm tracksTable">
|
<table class="text-sm tracksTable">
|
||||||
<tr class="font-book">
|
<tr class="font-book">
|
||||||
<th class="text-left">Filename</th>
|
<th class="text-left">{{ $strings.LabelFilename }}</th>
|
||||||
<th class="text-left">Size</th>
|
<th class="text-left">{{ $strings.LabelSize }}</th>
|
||||||
<th class="text-left">Type</th>
|
<th class="text-left">{{ $strings.LabelType }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-for="file in files">
|
<template v-for="file in files">
|
||||||
<tr :key="file.path">
|
<tr :key="file.path">
|
||||||
|
@ -6,15 +6,15 @@
|
|||||||
<span class="material-icons" style="font-size: 1.4rem">add</span>
|
<span class="material-icons" style="font-size: 1.4rem">add</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="h-0.5 bg-primary bg-opacity-50 w-full" /> -->
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<table id="accounts">
|
<table id="accounts">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Username</th>
|
<th>{{ $strings.LabelUsername }}</th>
|
||||||
<th class="w-20">Type</th>
|
<th class="w-20">{{ $strings.LabelAccountType }}</th>
|
||||||
<th class="hidden lg:table-cell">Activity</th>
|
<th class="hidden lg:table-cell">{{ $strings.LabelActivity }}</th>
|
||||||
<th class="w-32 hidden sm:table-cell">Last Seen</th>
|
<th class="w-32 hidden sm:table-cell">{{ $strings.LabelLastSeen }}</th>
|
||||||
<th class="w-32 hidden sm:table-cell">Created</th>
|
<th class="w-32 hidden sm:table-cell">{{ $strings.LabelCreatedAt }}</th>
|
||||||
<th class="w-32"></th>
|
<th class="w-32"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="user in users" :key="user.id" class="cursor-pointer" :class="user.isActive ? '' : 'bg-error bg-opacity-20'" @click="$router.push(`/config/users/${user.id}`)">
|
<tr v-for="user in users" :key="user.id" class="cursor-pointer" :class="user.isActive ? '' : 'bg-error bg-opacity-20'" @click="$router.push(`/config/users/${user.id}`)">
|
||||||
@ -88,7 +88,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
deleteUserClick(user) {
|
deleteUserClick(user) {
|
||||||
if (this.isDeletingUser) return
|
if (this.isDeletingUser) return
|
||||||
if (confirm(`Are you sure you want to permanently delete user "${user.username}"?`)) {
|
if (confirm(this.$getString('MessageRemoveUserWarning', [user.username]))) {
|
||||||
this.isDeletingUser = true
|
this.isDeletingUser = true
|
||||||
this.$axios
|
this.$axios
|
||||||
.$delete(`/api/users/${user.id}`)
|
.$delete(`/api/users/${user.id}`)
|
||||||
|
@ -14,12 +14,16 @@
|
|||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
<div v-if="!libraries.length" class="pb-4">
|
<div v-if="!libraries.length" class="pb-4">
|
||||||
<ui-btn @click="clickAddLibrary">Add your first library</ui-btn>
|
<ui-btn @click="clickAddLibrary">{{ $strings.ButtonAddYourFirstLibrary }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p v-if="libraries.length" class="text-xs mt-4 text-gray-200">*<strong>Force Re-Scan</strong> will scan all files again like a fresh scan. Audio file ID3 tags, OPF files, and text files will be probed/parsed and used for book details.</p>
|
<p v-if="libraries.length" class="text-xs mt-4 text-gray-200">
|
||||||
|
*<strong>{{ $strings.ButtonForceReScan }}</strong> {{ $strings.MessageForceReScanDescription }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p v-if="libraries.length && libraries.some((li) => li.mediaType === 'book')" class="text-xs mt-4 text-gray-200">**<strong>Match Books</strong> will attempt to match books in library with a book from the selected search provider and fill in empty details and cover art. Does not overwrite details.</p>
|
<p v-if="libraries.length && libraries.some((li) => li.mediaType === 'book')" class="text-xs mt-4 text-gray-200">
|
||||||
|
**<strong>{{ $strings.ButtonMatchBooks }}</strong> {{ $strings.MessageMatchBooksDescription }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<p class="text-xl font-book pl-4 hover:underline cursor-pointer" @click.stop="$emit('click', library)">{{ library.name }}</p>
|
<p class="text-xl font-book pl-4 hover:underline cursor-pointer" @click.stop="$emit('click', library)">{{ library.name }}</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-show="isHovering && !libraryScan" class="hidden md:block" small color="success" @click.stop="scan">Scan</ui-btn>
|
<ui-btn v-show="isHovering && !libraryScan" class="hidden md:block" small color="success" @click.stop="scan">{{ $strings.ButtonScan }}</ui-btn>
|
||||||
<ui-btn v-show="isHovering && !libraryScan" small color="bg" class="ml-2 hidden md:block" @click.stop="forceScan">Force Re-Scan</ui-btn>
|
<ui-btn v-show="isHovering && !libraryScan" small color="bg" class="ml-2 hidden md:block" @click.stop="forceScan">{{ $strings.ButtonForceReScan }}</ui-btn>
|
||||||
|
|
||||||
<ui-btn v-show="isHovering && !libraryScan && isBookLibrary" small color="bg" class="ml-2 hidden md:block" @click.stop="matchAll">Match Books</ui-btn>
|
<ui-btn v-show="isHovering && !libraryScan && isBookLibrary" small color="bg" class="ml-2 hidden md:block" @click.stop="matchAll">{{ $strings.ButtonMatchBooks }}</ui-btn>
|
||||||
|
|
||||||
<span v-if="isHovering && !libraryScan" class="!hidden md:!block material-icons text-xl text-gray-300 hover:text-gray-50 ml-4 cursor-pointer" @click.stop="editClick">edit</span>
|
<span v-if="isHovering && !libraryScan" class="!hidden md:!block material-icons text-xl text-gray-300 hover:text-gray-50 ml-4 cursor-pointer" @click.stop="editClick">edit</span>
|
||||||
<span v-if="!libraryScan && isHovering && !isDeleting" class="!hidden md:!block material-icons text-xl text-gray-300 ml-3 hover:text-gray-50 cursor-pointer" @click.stop="deleteClick">delete</span>
|
<span v-if="!libraryScan && isHovering && !isDeleting" class="!hidden md:!block material-icons text-xl text-gray-300 ml-3 hover:text-gray-50 cursor-pointer" @click.stop="deleteClick">delete</span>
|
||||||
|
@ -3,20 +3,20 @@
|
|||||||
<form class="w-full h-full px-2 md:px-4 py-6" @submit.prevent="submitForm">
|
<form class="w-full h-full px-2 md:px-4 py-6" @submit.prevent="submitForm">
|
||||||
<div class="flex flex-wrap -mx-1">
|
<div class="flex flex-wrap -mx-1">
|
||||||
<div class="w-full md:w-1/2 px-1">
|
<div class="w-full md:w-1/2 px-1">
|
||||||
<ui-text-input-with-label ref="titleInput" v-model="details.title" label="Title" />
|
<ui-text-input-with-label ref="titleInput" v-model="details.title" :label="$strings.LabelTitle" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1 mt-2 md:mt-0">
|
<div class="flex-grow px-1 mt-2 md:mt-0">
|
||||||
<ui-text-input-with-label ref="subtitleInput" v-model="details.subtitle" label="Subtitle" />
|
<ui-text-input-with-label ref="subtitleInput" v-model="details.subtitle" :label="$strings.LabelSubtitle" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap mt-2 -mx-1">
|
<div class="flex flex-wrap mt-2 -mx-1">
|
||||||
<div class="w-full md:w-3/4 px-1">
|
<div class="w-full md:w-3/4 px-1">
|
||||||
<!-- Authors filter only contains authors in this library, use query input to query all authors -->
|
<!-- Authors filter only contains authors in this library, use query input to query all authors -->
|
||||||
<ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" label="Authors" endpoint="authors/search" />
|
<ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" :label="$strings.LabelAuthors" endpoint="authors/search" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1 mt-2 md:mt-0">
|
<div class="flex-grow px-1 mt-2 md:mt-0">
|
||||||
<ui-text-input-with-label ref="publishYearInput" v-model="details.publishedYear" type="number" label="Publish Year" />
|
<ui-text-input-with-label ref="publishYearInput" v-model="details.publishedYear" type="number" :label="$strings.LabelPublishYear" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -26,20 +26,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" label="Description" class="mt-2" />
|
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" />
|
||||||
|
|
||||||
<div class="flex flex-wrap mt-2 -mx-1">
|
<div class="flex flex-wrap mt-2 -mx-1">
|
||||||
<div class="w-full md:w-1/2 px-1">
|
<div class="w-full md:w-1/2 px-1">
|
||||||
<ui-multi-select ref="genresSelect" v-model="details.genres" label="Genres" :items="genres" />
|
<ui-multi-select ref="genresSelect" v-model="details.genres" :label="$strings.LabelGenres" :items="genres" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1 mt-2 md:mt-0">
|
<div class="flex-grow px-1 mt-2 md:mt-0">
|
||||||
<ui-multi-select ref="tagsSelect" v-model="newTags" label="Tags" :items="tags" />
|
<ui-multi-select ref="tagsSelect" v-model="newTags" :label="$strings.LabelTags" :items="tags" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap mt-2 -mx-1">
|
<div class="flex flex-wrap mt-2 -mx-1">
|
||||||
<div class="w-full md:w-1/2 px-1">
|
<div class="w-full md:w-1/2 px-1">
|
||||||
<ui-multi-select ref="narratorsSelect" v-model="details.narrators" label="Narrators" :items="narrators" />
|
<ui-multi-select ref="narratorsSelect" v-model="details.narrators" :label="$strings.LabelNarrators" :items="narrators" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 md:w-1/4 px-1 mt-2 md:mt-0">
|
<div class="w-1/2 md:w-1/4 px-1 mt-2 md:mt-0">
|
||||||
<ui-text-input-with-label ref="isbnInput" v-model="details.isbn" label="ISBN" />
|
<ui-text-input-with-label ref="isbnInput" v-model="details.isbn" label="ISBN" />
|
||||||
@ -51,14 +51,14 @@
|
|||||||
|
|
||||||
<div class="flex flex-wrap mt-2 -mx-1">
|
<div class="flex flex-wrap mt-2 -mx-1">
|
||||||
<div class="w-full md:w-1/2 px-1">
|
<div class="w-full md:w-1/2 px-1">
|
||||||
<ui-text-input-with-label ref="publisherInput" v-model="details.publisher" label="Publisher" />
|
<ui-text-input-with-label ref="publisherInput" v-model="details.publisher" :label="$strings.LabelPublisher" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 md:w-1/4 px-1 mt-2 md:mt-0">
|
<div class="w-1/2 md:w-1/4 px-1 mt-2 md:mt-0">
|
||||||
<ui-text-input-with-label ref="languageInput" v-model="details.language" label="Language" />
|
<ui-text-input-with-label ref="languageInput" v-model="details.language" :label="$strings.LabelLanguage" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1 pt-6 mt-2 md:mt-0">
|
<div class="flex-grow px-1 pt-6 mt-2 md:mt-0">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<ui-checkbox v-model="details.explicit" label="Explicit" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
<ui-checkbox v-model="details.explicit" :label="$strings.LabelExplicit" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,22 +2,22 @@
|
|||||||
<div class="w-full py-2">
|
<div class="w-full py-2">
|
||||||
<div class="flex -mb-px">
|
<div class="flex -mb-px">
|
||||||
<div class="w-1/2 h-8 rounded-tl-md relative border border-black-200 flex items-center justify-center cursor-pointer" :class="!showAdvancedView ? 'text-white bg-bg hover:bg-opacity-60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary bg-opacity-70 hover:bg-opacity-60'" @click="showAdvancedView = false">
|
<div class="w-1/2 h-8 rounded-tl-md relative border border-black-200 flex items-center justify-center cursor-pointer" :class="!showAdvancedView ? 'text-white bg-bg hover:bg-opacity-60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary bg-opacity-70 hover:bg-opacity-60'" @click="showAdvancedView = false">
|
||||||
<p class="text-sm">Scheduler</p>
|
<p class="text-sm">{{ $strings.HeaderSchedule }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 h-8 rounded-tr-md relative border border-black-200 flex items-center justify-center -ml-px cursor-pointer" :class="showAdvancedView ? 'text-white bg-bg hover:bg-opacity-60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary bg-opacity-70 hover:bg-opacity-60'" @click="showAdvancedView = true">
|
<div class="w-1/2 h-8 rounded-tr-md relative border border-black-200 flex items-center justify-center -ml-px cursor-pointer" :class="showAdvancedView ? 'text-white bg-bg hover:bg-opacity-60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary bg-opacity-70 hover:bg-opacity-60'" @click="showAdvancedView = true">
|
||||||
<p class="text-sm">Advanced</p>
|
<p class="text-sm">{{ $strings.HeaderAdvanced }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-2 py-4 md:p-4 border border-black-200 rounded-b-md mr-px" style="min-height: 280px">
|
<div class="px-2 py-4 md:p-4 border border-black-200 rounded-b-md mr-px" style="min-height: 280px">
|
||||||
<template v-if="!showAdvancedView">
|
<template v-if="!showAdvancedView">
|
||||||
<ui-dropdown v-model="selectedInterval" @input="updateCron" label="Interval" :items="intervalOptions" class="mb-2" />
|
<ui-dropdown v-model="selectedInterval" @input="updateCron" :label="$strings.LabelInterval" :items="intervalOptions" class="mb-2" />
|
||||||
|
|
||||||
<ui-multi-select-dropdown v-if="selectedInterval === 'custom'" v-model="selectedWeekdays" @input="updateCron" label="Weekdays to run" :items="weekdays" />
|
<ui-multi-select-dropdown v-if="selectedInterval === 'custom'" v-model="selectedWeekdays" @input="updateCron" :label="$string.LabelWeekdaysToRun" :items="weekdays" />
|
||||||
|
|
||||||
<div v-if="(selectedWeekdays.length && selectedInterval === 'custom') || selectedInterval === 'daily'" class="flex items-center py-2">
|
<div v-if="(selectedWeekdays.length && selectedInterval === 'custom') || selectedInterval === 'daily'" class="flex items-center py-2">
|
||||||
<ui-text-input-with-label v-model="selectedHour" @input="updateCron" @blur="hourBlur" type="number" label="Hour" class="max-w-20" />
|
<ui-text-input-with-label v-model="selectedHour" @input="updateCron" @blur="hourBlur" type="number" :label="$strings.LabelHour" class="max-w-20" />
|
||||||
<p class="text-xl px-2 mt-4">:</p>
|
<p class="text-xl px-2 mt-4">:</p>
|
||||||
<ui-text-input-with-label v-model="selectedMinute" @input="updateCron" @blur="minuteBlur" type="number" label="Minute" class="max-w-20" />
|
<ui-text-input-with-label v-model="selectedMinute" @input="updateCron" @blur="minuteBlur" type="number" :label="$strings.LabelMinute" class="max-w-20" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="description" class="w-full bg-primary bg-opacity-75 rounded-xl p-2 md:p-4 text-center mt-2">
|
<div v-if="description" class="w-full bg-primary bg-opacity-75 rounded-xl p-2 md:p-4 text-center mt-2">
|
||||||
@ -25,15 +25,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p class="px-1 text-sm font-semibold">Cron Expression</p>
|
<p class="px-1 text-sm font-semibold">{{ $strings.LabelCronExpression }}</p>
|
||||||
<ui-text-input ref="customExpressionInput" v-model="customCronExpression" @blur="cronExpressionBlur" label="Cron Expression" :padding-y="2" text-center class="w-full text-2xl md:text-4xl -tracking-widest mb-4 font-mono" />
|
<ui-text-input ref="customExpressionInput" v-model="customCronExpression" @blur="cronExpressionBlur" :padding-y="2" text-center class="w-full text-2xl md:text-4xl -tracking-widest mb-4 font-mono" />
|
||||||
|
|
||||||
<div class="flex items-center justify-center">
|
<div class="flex items-center justify-center">
|
||||||
<widgets-loading-spinner v-if="isValidating" class="mr-2" />
|
<widgets-loading-spinner v-if="isValidating" class="mr-2" />
|
||||||
<span v-else class="material-icons-outlined mr-2 text-xl" :class="isValid ? 'text-success' : 'text-error'">{{ isValid ? 'check_circle_outline' : 'error_outline' }}</span>
|
<span v-else class="material-icons-outlined mr-2 text-xl" :class="isValid ? 'text-success' : 'text-error'">{{ isValid ? 'check_circle_outline' : 'error_outline' }}</span>
|
||||||
<p v-if="isValidating" class="text-gray-300 text-base md:text-lg text-center">Checking cron...</p>
|
<p v-if="isValidating" class="text-gray-300 text-base md:text-lg text-center">{{ $strings.MessageCheckingCron }}</p>
|
||||||
<p v-else-if="customCronError" class="text-error text-base md:text-lg text-center">{{ customCronError }}</p>
|
<p v-else-if="customCronError" class="text-error text-base md:text-lg text-center">{{ customCronError }}</p>
|
||||||
<p v-else class="text-success text-base md:text-lg text-center">Valid cron expression</p>
|
<p v-else class="text-success text-base md:text-lg text-center">{{ $strings.MessageValidCronExpression }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -137,31 +137,31 @@ export default {
|
|||||||
weekdays() {
|
weekdays() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
text: 'Sunday',
|
text: this.$strings.WeekdaySunday,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Monday',
|
text: this.$strings.WeekdayMonday,
|
||||||
value: 1
|
value: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Tuesday',
|
text: this.$strings.WeekdayTuesday,
|
||||||
value: 2
|
value: 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Wednesday',
|
text: this.$strings.WeekdayWednesday,
|
||||||
value: 3
|
value: 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Thursday',
|
text: this.$strings.WeekdayThursday,
|
||||||
value: 4
|
value: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Friday',
|
text: this.$strings.WeekdayFriday,
|
||||||
value: 5
|
value: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Saturday',
|
text: this.$strings.WeekdaySaturday,
|
||||||
value: 6
|
value: 6
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ui-multi-select-query-input v-model="seriesItems" text-key="displayName" label="Series" :disabled="disabled" readonly show-edit @edit="editSeriesItem" @add="addNewSeries" />
|
<ui-multi-select-query-input v-model="seriesItems" text-key="displayName" :label="$strings.LabelSeries" :disabled="disabled" readonly show-edit @edit="editSeriesItem" @add="addNewSeries" />
|
||||||
|
|
||||||
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" @submit="submitSeriesForm" />
|
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" @submit="submitSeriesForm" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,23 +8,23 @@
|
|||||||
<span class="material-icons text-base">edit</span>
|
<span class="material-icons text-base">edit</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<p class="text-base">Duration:</p>
|
<p class="text-base">{{ $strings.LabelDuration }}:</p>
|
||||||
<p class="text-base font-mono ml-8">{{ $secondsToTimestamp(mediaDurationRounded) }}</p>
|
<p class="text-base font-mono ml-8">{{ $secondsToTimestamp(mediaDurationRounded) }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap-reverse justify-center py-4">
|
<div class="flex flex-wrap-reverse justify-center py-4">
|
||||||
<div class="w-full max-w-3xl py-4">
|
<div class="w-full max-w-3xl py-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<p class="text-lg mb-4 font-semibold">Audiobook Chapters</p>
|
<p class="text-lg mb-4 font-semibold">{{ $strings.HeaderChapters }}</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-checkbox v-model="showSecondInputs" checkbox-bg="primary" small label-class="text-sm text-gray-200 pl-1" label="Show seconds" class="mx-2" />
|
<ui-checkbox v-model="showSecondInputs" checkbox-bg="primary" small label-class="text-sm text-gray-200 pl-1" label="Show seconds" class="mx-2" />
|
||||||
<div class="w-40" />
|
<div class="w-40" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center mb-3 py-1">
|
<div class="flex items-center mb-3 py-1">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn v-if="newChapters.length > 1" :color="showShiftTimes ? 'bg' : 'primary'" small @click="showShiftTimes = !showShiftTimes">Shift Times</ui-btn>
|
<ui-btn v-if="newChapters.length > 1" :color="showShiftTimes ? 'bg' : 'primary'" small @click="showShiftTimes = !showShiftTimes">{{ $strings.ButtonShiftTimes }}</ui-btn>
|
||||||
<ui-btn color="primary" small class="mx-2" @click="showFindChaptersModal = true">Lookup</ui-btn>
|
<ui-btn color="primary" small class="mx-2" @click="showFindChaptersModal = true">{{ $strings.ButtonLookup }}</ui-btn>
|
||||||
<ui-btn color="success" small @click="saveChapters">Save</ui-btn>
|
<ui-btn color="success" small @click="saveChapters">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
<div class="w-40" />
|
<div class="w-40" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -34,13 +34,13 @@
|
|||||||
<div class="w-12"></div>
|
<div class="w-12"></div>
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<p class="text-sm mb-1 font-semibold pr-2">Time to shift in seconds</p>
|
<p class="text-sm mb-1 font-semibold pr-2">{{ $strings.LabelTimeToShift }}</p>
|
||||||
<ui-text-input v-model="shiftAmount" type="number" class="max-w-20" style="height: 30px" />
|
<ui-text-input v-model="shiftAmount" type="number" class="max-w-20" style="height: 30px" />
|
||||||
<ui-btn color="primary" class="mx-1" small @click="shiftChapterTimes">Add</ui-btn>
|
<ui-btn color="primary" class="mx-1" small @click="shiftChapterTimes">{{ $strings.ButtonAdd }}</ui-btn>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<span class="material-icons text-gray-200 hover:text-white cursor-pointer" @click="showShiftTimes = false">close</span>
|
<span class="material-icons text-gray-200 hover:text-white cursor-pointer" @click="showShiftTimes = false">close</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs py-1.5 text-gray-300 max-w-md">Note: First chapter start time must remain at 0:00 and the last chapter start time cannot exceed this audiobooks duration.</p>
|
<p class="text-xs py-1.5 text-gray-300 max-w-md">{{ $strings.NoteChapterEditorTimes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-40"></div>
|
<div class="w-40"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -49,8 +49,8 @@
|
|||||||
|
|
||||||
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
||||||
<div class="w-12"></div>
|
<div class="w-12"></div>
|
||||||
<div class="w-32 px-2">Start</div>
|
<div class="w-32 px-2">{{ $strings.LabelStart }}</div>
|
||||||
<div class="flex-grow px-2">Title</div>
|
<div class="flex-grow px-2">{{ $strings.LabelTitle }}</div>
|
||||||
<div class="w-40"></div>
|
<div class="w-40"></div>
|
||||||
</div>
|
</div>
|
||||||
<template v-for="chapter in newChapters">
|
<template v-for="chapter in newChapters">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
<span class="material-icons-outlined text-base">remove</span>
|
<span class="material-icons-outlined text-base">remove</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ui-tooltip text="Insert chapter below" direction="bottom">
|
<ui-tooltip :text="$strings.MessageInsertChapterBelow" direction="bottom">
|
||||||
<button class="w-7 h-7 rounded-full flex items-center justify-center text-gray-300 hover:text-success transform hover:scale-110 duration-150" @click="addChapter(chapter)">
|
<button class="w-7 h-7 rounded-full flex items-center justify-center text-gray-300 hover:text-success transform hover:scale-110 duration-150" @click="addChapter(chapter)">
|
||||||
<span class="material-icons text-lg">add</span>
|
<span class="material-icons text-lg">add</span>
|
||||||
</button>
|
</button>
|
||||||
@ -93,11 +93,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full max-w-xl py-4">
|
<div class="w-full max-w-xl py-4">
|
||||||
<p class="text-lg mb-4 font-semibold py-1">Audio Tracks</p>
|
<p class="text-lg mb-4 font-semibold py-1">{{ $strings.HeaderAudioTracks }}</p>
|
||||||
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
<div class="flex text-xs uppercase text-gray-300 font-semibold mb-2">
|
||||||
<div class="flex-grow">Filename</div>
|
<div class="flex-grow">{{ $strings.LabelFilename }}</div>
|
||||||
<div class="w-20">Duration</div>
|
<div class="w-20">{{ $strings.LabelDuration }}</div>
|
||||||
<div class="w-20 text-center">Chapters</div>
|
<div class="w-20 text-center">{{ $strings.HeaderChapters }}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-for="track in audioTracks">
|
<template v-for="track in audioTracks">
|
||||||
<div :key="track.ino" class="flex items-center py-2" :class="currentTrackIndex === track.index && isPlayingChapter ? 'bg-success bg-opacity-10' : ''">
|
<div :key="track.ino" class="flex items-center py-2" :class="currentTrackIndex === track.index && isPlayingChapter ? 'bg-success bg-opacity-10' : ''">
|
||||||
@ -122,14 +122,14 @@
|
|||||||
<modals-modal v-model="showFindChaptersModal" name="edit-book" :width="500" :processing="findingChapters">
|
<modals-modal v-model="showFindChaptersModal" name="edit-book" :width="500" :processing="findingChapters">
|
||||||
<template #outer>
|
<template #outer>
|
||||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden pointer-events-none">
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden pointer-events-none">
|
||||||
<p class="font-book text-3xl text-white truncate pointer-events-none">Find Chapters</p>
|
<p class="font-book text-3xl text-white truncate pointer-events-none">{{ $strings.HeaderFindChapters }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="w-full h-full max-h-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative">
|
<div class="w-full h-full max-h-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative">
|
||||||
<div v-if="!chapterData" class="flex p-20">
|
<div v-if="!chapterData" class="flex p-20">
|
||||||
<ui-text-input-with-label v-model="asinInput" label="ASIN" />
|
<ui-text-input-with-label v-model="asinInput" label="ASIN" />
|
||||||
<ui-dropdown v-model="regionInput" label="Region" small :items="audibleRegions" class="w-32 mx-1" />
|
<ui-dropdown v-model="regionInput" :label="$strings.LabelRegion" small :items="audibleRegions" class="w-32 mx-1" />
|
||||||
<ui-btn small color="primary" class="mt-5" @click="findChapters">Find</ui-btn>
|
<ui-btn small color="primary" class="mt-5" @click="findChapters">{{ $strings.ButtonSearch }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="w-full p-4">
|
<div v-else class="w-full p-4">
|
||||||
<div class="flex justify-between mb-4">
|
<div class="flex justify-between mb-4">
|
||||||
@ -148,8 +148,8 @@
|
|||||||
<widgets-alert v-else-if="chapterData.runtimeLengthSec < mediaDurationRounded" type="warning" class="mb-2"> Your audiobook duration is longer than the duration found </widgets-alert>
|
<widgets-alert v-else-if="chapterData.runtimeLengthSec < mediaDurationRounded" type="warning" class="mb-2"> Your audiobook duration is longer than the duration found </widgets-alert>
|
||||||
|
|
||||||
<div class="flex py-0.5 text-xs font-semibold uppercase text-gray-300 mb-1">
|
<div class="flex py-0.5 text-xs font-semibold uppercase text-gray-300 mb-1">
|
||||||
<div class="w-24 px-2">Start</div>
|
<div class="w-24 px-2">{{ $strings.LabelStart }}</div>
|
||||||
<div class="flex-grow px-2">Title</div>
|
<div class="flex-grow px-2">{{ $strings.LabelTitle }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full max-h-80 overflow-y-auto my-2">
|
<div class="w-full max-h-80 overflow-y-auto my-2">
|
||||||
<div v-for="(chapter, index) in chapterData.chapters" :key="index" class="flex py-0.5 text-xs" :class="chapter.startOffsetSec > mediaDuration ? 'bg-error bg-opacity-20' : chapter.startOffsetSec + chapter.lengthMs / 1000 > mediaDuration ? 'bg-warning bg-opacity-20' : index % 2 === 0 ? 'bg-primary bg-opacity-30' : ''">
|
<div v-for="(chapter, index) in chapterData.chapters" :key="index" class="flex py-0.5 text-xs" :class="chapter.startOffsetSec > mediaDuration ? 'bg-error bg-opacity-20' : chapter.startOffsetSec + chapter.lengthMs / 1000 > mediaDuration ? 'bg-warning bg-opacity-20' : index % 2 === 0 ? 'bg-primary bg-opacity-30' : ''">
|
||||||
@ -172,12 +172,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center pt-2">
|
<div class="flex items-center pt-2">
|
||||||
<ui-btn small color="primary" class="mr-1" @click="applyChapterNamesOnly">Map Chapter Titles</ui-btn>
|
<ui-btn small color="primary" class="mr-1" @click="applyChapterNamesOnly">{{ $strings.ButtonMapChapterTitles }}</ui-btn>
|
||||||
<ui-tooltip text="Map chapter titles to your existing audiobook chapters without adjusting timestamps" direction="top">
|
<ui-tooltip :text="$strings.MessageMapChapterTitles" direction="top">
|
||||||
<span class="material-icons-outlined">info</span>
|
<span class="material-icons-outlined">info</span>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn small color="success" @click="applyChapterData">Apply Chapters</ui-btn>
|
<ui-btn small color="success" @click="applyChapterData">{{ $strings.ButtonApplyChapters }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div id="page-wrapper" class="bg-bg page p-8 overflow-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
|
<div id="page-wrapper" class="bg-bg page p-8 overflow-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
|
||||||
<div class="flex items-center justify-center mb-6">
|
<div class="flex items-center justify-center mb-6">
|
||||||
<div class="w-full max-w-2xl">
|
<div class="w-full max-w-2xl">
|
||||||
<p class="text-2xl mb-2">Audiobook File Management Tools</p>
|
<p class="text-2xl mb-2">{{ $strings.HeaderAudiobookTools }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full max-w-2xl">
|
<div class="w-full max-w-2xl">
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
|
@ -2,15 +2,16 @@
|
|||||||
<div class="w-full h-full">
|
<div class="w-full h-full">
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
||||||
<div class="flex items-center mb-2">
|
<div class="flex items-center mb-2">
|
||||||
<h1 class="text-xl">Backups</h1>
|
<h1 class="text-xl">{{ $strings.HeaderBackups }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-base mb-4 text-gray-300">Backups include users, user progress, library item details, server settings, and images stored in <span class="font-mono text-gray-100">/metadata/items</span> & <span class="font-mono text-gray-100">/metadata/authors</span>. <br />Backups <strong>do not</strong> include any files stored in your library folders.</p>
|
<p class="text-base mb-2 text-gray-300">{{ $strings.MessageBackupsDescription }} <span class="font-mono text-gray-100">/metadata/items</span> & <span class="font-mono text-gray-100">/metadata/authors</span>.</p>
|
||||||
|
<p class="text-base mb-4 text-gray-300">{{ $strings.MessageBackupsNote }}</p>
|
||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" />
|
<ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" />
|
||||||
<ui-tooltip :text="backupsTooltip">
|
<ui-tooltip :text="$strings.LabelBackupsEnableAutomaticBackupsHelp">
|
||||||
<p class="pl-4 text-lg">Enable automatic backups <span class="material-icons icon-text">info_outlined</span></p>
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsEnableAutomaticBackups }} <span class="material-icons icon-text">info_outlined</span></p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -25,16 +26,16 @@
|
|||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-text-input type="number" v-model="backupsToKeep" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
<ui-text-input type="number" v-model="backupsToKeep" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
||||||
|
|
||||||
<ui-tooltip :text="numBackupsToKeepTooltip">
|
<ui-tooltip :text="$strings.LabelBackupsNumberToKeepHelp">
|
||||||
<p class="pl-4 text-lg">Number of backups to keep <span class="material-icons icon-text">info_outlined</span></p>
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsNumberToKeep }} <span class="material-icons icon-text">info_outlined</span></p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-text-input type="number" v-model="maxBackupSize" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
<ui-text-input type="number" v-model="maxBackupSize" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
||||||
|
|
||||||
<ui-tooltip :text="maxBackupSizeTooltip">
|
<ui-tooltip :text="$strings.LabelBackupsMaxBackupSizeHelp">
|
||||||
<p class="pl-4 text-lg">Maximum backup size (in GB) <span class="material-icons icon-text">info_outlined</span></p>
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsMaxBackupSize }} <span class="material-icons icon-text">info_outlined</span></p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -55,10 +56,7 @@ export default {
|
|||||||
maxBackupSize: 1,
|
maxBackupSize: 1,
|
||||||
cronExpression: '',
|
cronExpression: '',
|
||||||
newServerSettings: {},
|
newServerSettings: {},
|
||||||
showCronBuilder: false,
|
showCronBuilder: false
|
||||||
backupsTooltip: 'Backups saved in /metadata/backups',
|
|
||||||
numBackupsToKeepTooltip: 'Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.',
|
|
||||||
maxBackupSizeTooltip: 'As a safeguard against misconfiguration, backups will fail if they exceed the configured size.'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -109,9 +109,9 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.scannerPreferOverdriveMediaMarker" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOverdriveMediaMarker', val)" />
|
<ui-toggle-switch v-model="newServerSettings.scannerPreferOverdriveMediaMarker" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOverdriveMediaMarker', val)" />
|
||||||
<ui-tooltip :text="tooltips.scannerPreferOverdriveMediaMarker">
|
<ui-tooltip :text="$strings.LabelSettingsOverdriveMediaMarkersHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Use Overdrive Media Markers for chapters
|
{{ $strings.LabelSettingsOverdriveMediaMarkers }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -119,9 +119,9 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.scannerPreferAudioMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferAudioMetadata', val)" />
|
<ui-toggle-switch v-model="newServerSettings.scannerPreferAudioMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferAudioMetadata', val)" />
|
||||||
<ui-tooltip :text="tooltips.scannerPreferAudioMetadata">
|
<ui-tooltip :text="$strings.LabelSettingsPreferAudioMetadataHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Prefer audio metadata
|
{{ $strings.LabelSettingsPreferAudioMetadata }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -129,9 +129,9 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.scannerPreferOpfMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOpfMetadata', val)" />
|
<ui-toggle-switch v-model="newServerSettings.scannerPreferOpfMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOpfMetadata', val)" />
|
||||||
<ui-tooltip :text="tooltips.scannerPreferOpfMetadata">
|
<ui-tooltip :text="$strings.LabelSettingsPreferOPFMetadataHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Prefer OPF metadata
|
{{ $strings.LabelSettingsPreferOPFMetadata }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -139,9 +139,9 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
|
<ui-toggle-switch v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
|
||||||
<ui-tooltip :text="tooltips.scannerPreferMatchedMetadata">
|
<ui-tooltip :text="$strings.LabelSettingsPreferMatchedMetadataHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Prefer matched metadata
|
{{ $strings.LabelSettingsPreferMatchedMetadata }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -149,33 +149,23 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.scannerDisableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', val)" />
|
<ui-toggle-switch v-model="newServerSettings.scannerDisableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', val)" />
|
||||||
<ui-tooltip :text="tooltips.scannerDisableWatcher">
|
<ui-tooltip :text="$strings.LabelSettingsDisableWatcherHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Disable Watcher
|
{{ $strings.LabelSettingsDisableWatcher }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="flex items-center py-2">
|
|
||||||
<ui-text-input type="number" v-model="newServerSettings.scannerMaxThreads" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateScannerMaxThreads" />
|
|
||||||
<ui-tooltip :text="tooltips.scannerMaxThreads">
|
|
||||||
<p class="pl-4">
|
|
||||||
Max # of threads to use
|
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
|
||||||
</p>
|
|
||||||
</ui-tooltip>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<h2 class="font-semibold">{{ $strings.HeaderSettingsExperimental }}</h2>
|
<h2 class="font-semibold">{{ $strings.HeaderSettingsExperimental }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="showExperimentalFeatures" />
|
<ui-toggle-switch v-model="showExperimentalFeatures" />
|
||||||
<ui-tooltip :text="tooltips.experimentalFeatures">
|
<ui-tooltip :text="$strings.LabelSettingsExperimentalFeaturesHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Experimental features
|
{{ $strings.LabelSettingsExperimentalFeatures }}
|
||||||
<a href="https://github.com/advplyr/audiobookshelf/discussions/75" target="_blank">
|
<a href="https://github.com/advplyr/audiobookshelf/discussions/75" target="_blank">
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</a>
|
</a>
|
||||||
@ -185,9 +175,9 @@
|
|||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-toggle-switch v-model="newServerSettings.enableEReader" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('enableEReader', val)" />
|
<ui-toggle-switch v-model="newServerSettings.enableEReader" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('enableEReader', val)" />
|
||||||
<ui-tooltip :text="tooltips.enableEReader">
|
<ui-tooltip :text="$strings.LabelSettingsEnableEReaderHelp">
|
||||||
<p class="pl-4">
|
<p class="pl-4">
|
||||||
Enable e-reader for all users
|
{{ $strings.LabelSettingsEnableEReader }}
|
||||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@ -228,7 +218,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<p class="pl-4 pr-2 text-sm font-book text-yellow-400">
|
<p class="pl-4 pr-2 text-sm font-book text-yellow-400">
|
||||||
Join us on
|
{{ $strings.MessageJoinUsOn }}
|
||||||
<a class="underline" href="https://discord.gg/pJsjuNCKRq" target="_blank">discord</a>
|
<a class="underline" href="https://discord.gg/pJsjuNCKRq" target="_blank">discord</a>
|
||||||
</p>
|
</p>
|
||||||
<a href="https://discord.gg/pJsjuNCKRq" target="_blank" class="text-white hover:text-gray-200 hover:scale-150 hover:rotate-6 transform duration-500">
|
<a href="https://discord.gg/pJsjuNCKRq" target="_blank" class="text-white hover:text-gray-200 hover:scale-150 hover:rotate-6 transform duration-500">
|
||||||
@ -276,17 +266,6 @@ export default {
|
|||||||
useBookshelfView: false,
|
useBookshelfView: false,
|
||||||
isPurgingCache: false,
|
isPurgingCache: false,
|
||||||
newServerSettings: {},
|
newServerSettings: {},
|
||||||
tooltips: {
|
|
||||||
experimentalFeatures: 'Features in development that could use your feedback and help testing. Click to open github discussion.',
|
|
||||||
scannerDisableWatcher: 'Disables the automatic adding/updating of items when file changes are detected. *Requires server restart',
|
|
||||||
scannerPreferOpfMetadata: 'OPF file metadata will be used for book details over folder names',
|
|
||||||
scannerPreferMatchedMetadata: 'Matched data will overide book details when using Quick Match',
|
|
||||||
scannerPreferAudioMetadata: 'Audio file ID3 meta tags will be used for book details over folder names',
|
|
||||||
enableEReader: 'E-reader is still a work in progress, but use this setting to open it up to all your users (or use the "Experimental Features" toggle just for use by you)',
|
|
||||||
scannerPreferOverdriveMediaMarker: 'MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically',
|
|
||||||
scannerUseSingleThreadedProber: 'The old scanner used a single thread. Leaving it in to use as a comparison for now.',
|
|
||||||
scannerMaxThreads: 'Number of concurrent media files to scan at a time. Value of 1 will be a slower scan but less CPU usage. <br><br>Value of 0 defaults to # of CPU cores for this server times 2 (i.e. 4-core CPU will be 8)'
|
|
||||||
},
|
|
||||||
showConfirmPurgeCache: false
|
showConfirmPurgeCache: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -317,26 +296,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateScannerMaxThreads(val) {
|
|
||||||
if (!val || isNaN(val)) {
|
|
||||||
this.$toast.error('Invalid max threads must be a number')
|
|
||||||
this.newServerSettings.scannerMaxThreads = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (Number(val) < 0) {
|
|
||||||
this.$toast.error('Max threads must be >= 0')
|
|
||||||
this.newServerSettings.scannerMaxThreads = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (Math.round(Number(val)) !== Number(val)) {
|
|
||||||
this.$toast.error('Max threads must be an integer')
|
|
||||||
this.newServerSettings.scannerMaxThreads = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.updateServerSettings({
|
|
||||||
scannerMaxThreads: Number(val)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateSortingPrefixes(val) {
|
updateSortingPrefixes(val) {
|
||||||
if (!val || !val.length) {
|
if (!val || !val.length) {
|
||||||
this.$toast.error('Must have at least 1 prefix')
|
this.$toast.error('Must have at least 1 prefix')
|
||||||
@ -390,7 +349,7 @@ export default {
|
|||||||
this.useBookshelfView = this.newServerSettings.bookshelfView != this.$constants.BookshelfView.DETAIL
|
this.useBookshelfView = this.newServerSettings.bookshelfView != this.$constants.BookshelfView.DETAIL
|
||||||
},
|
},
|
||||||
resetLibraryItems() {
|
resetLibraryItems() {
|
||||||
if (confirm('WARNING! This action will remove all library items from the database including any updates or matches you have made. This does not do anything to your actual files. Shall we continue?')) {
|
if (confirm(this.$strings.MessageRemoveAllItemsWarning)) {
|
||||||
this.isResettingLibraryItems = true
|
this.isResettingLibraryItems = true
|
||||||
this.$axios
|
this.$axios
|
||||||
.$delete('/api/items/all')
|
.$delete('/api/items/all')
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
||||||
<h1 class="text-xl">Stats for library {{ currentLibraryName }}</h1>
|
<h1 class="text-xl">{{ $strings.HeaderLibraryStats }}: {{ currentLibraryName }}</h1>
|
||||||
<stats-preview-icons v-if="totalItems" :library-stats="libraryStats" />
|
<stats-preview-icons v-if="totalItems" :library-stats="libraryStats" />
|
||||||
|
|
||||||
<div class="flex lg:flex-row flex-wrap justify-between flex-col mt-8">
|
<div class="flex lg:flex-row flex-wrap justify-between flex-col mt-8">
|
||||||
<div class="w-80 my-6 mx-auto">
|
<div class="w-80 my-6 mx-auto">
|
||||||
<h1 class="text-2xl mb-4 font-book">Top 5 Genres</h1>
|
<h1 class="text-2xl mb-4 font-book">{{ $strings.HeaderStatsTop5Genres }}</h1>
|
||||||
<p v-if="!top5Genres.length">No Genres</p>
|
<p v-if="!top5Genres.length">{{ $strings.MessageNoGenres }}</p>
|
||||||
<template v-for="genre in top5Genres">
|
<template v-for="genre in top5Genres">
|
||||||
<div :key="genre.genre" class="w-full py-2">
|
<div :key="genre.genre" class="w-full py-2">
|
||||||
<div class="flex items-end mb-1">
|
<div class="flex items-end mb-1">
|
||||||
@ -23,8 +23,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-80 my-6 mx-auto">
|
<div class="w-80 my-6 mx-auto">
|
||||||
<h1 class="text-2xl mb-4 font-book">Top 10 Authors</h1>
|
<h1 class="text-2xl mb-4 font-book">{{ $strings.HeaderStatsTop10Authors }}</h1>
|
||||||
<p v-if="!top10Authors.length">No Authors</p>
|
<p v-if="!top10Authors.length">{{ $strings.MessageNoAuthors }}</p>
|
||||||
<template v-for="(author, index) in top10Authors">
|
<template v-for="(author, index) in top10Authors">
|
||||||
<div :key="author.id" class="w-full py-2">
|
<div :key="author.id" class="w-full py-2">
|
||||||
<div class="flex items-center mb-1">
|
<div class="flex items-center mb-1">
|
||||||
@ -42,8 +42,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-80 my-6 mx-auto">
|
<div class="w-80 my-6 mx-auto">
|
||||||
<h1 class="text-2xl mb-4 font-book">Longest Items (hrs)</h1>
|
<h1 class="text-2xl mb-4 font-book">{{ $strings.HeaderStatsLongestItems }}</h1>
|
||||||
<p v-if="!top10LongestItems.length">No Items</p>
|
<p v-if="!top10LongestItems.length">{{ $strings.MessageNoItems }}</p>
|
||||||
<template v-for="(ab, index) in top10LongestItems">
|
<template v-for="(ab, index) in top10LongestItems">
|
||||||
<div :key="index" class="w-full py-2">
|
<div :key="index" class="w-full py-2">
|
||||||
<div class="flex items-center mb-1">
|
<div class="flex items-center mb-1">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="w-full h-full">
|
<div class="w-full h-full">
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
||||||
<div class="flex items-center mb-2">
|
<div class="flex items-center mb-2">
|
||||||
<h1 class="text-xl">Logs</h1>
|
<h1 class="text-xl">{{ $strings.HeaderLogs }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between mb-2 place-items-end">
|
<div class="flex justify-between mb-2 place-items-end">
|
||||||
<ui-text-input ref="input" v-model="search" placeholder="Search filter.." @input="inputUpdate" clearable class="w-full sm:w-40 h-8 text-sm sm:mb-0" />
|
<ui-text-input ref="input" v-model="search" placeholder="Search filter.." @input="inputUpdate" clearable class="w-full sm:w-40 h-8 text-sm sm:mb-0" />
|
||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!logs.length" class="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-center">
|
<div v-if="!logs.length" class="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-center">
|
||||||
<p class="text-xl text-gray-200 mb-2">No Logs</p>
|
<p class="text-xl text-gray-200 mb-2">{{ $strings.MessageNoLogs }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-3 md:p-8 mb-2 max-w-3xl mx-auto">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-3 md:p-8 mb-2 max-w-3xl mx-auto">
|
||||||
<h2 class="text-xl font-semibold mb-4">Apprise Notification Settings</h2>
|
<h2 class="text-xl font-semibold mb-4">{{ $strings.HeaderAppriseNotificationSettings }}</h2>
|
||||||
<p class="mb-6 text-gray-200">
|
<p class="mb-6 text-gray-200">
|
||||||
In order to use this feature you will need to have an instance of <a href="https://github.com/caronc/apprise-api" target="_blank" class="hover:underline text-blue-400 hover:text-blue-300">Apprise API</a> running or an api that will handle those same requests. <br />The Apprise API Url should be the full URL path to send the notification, e.g., if your API instance is served at
|
In order to use this feature you will need to have an instance of <a href="https://github.com/caronc/apprise-api" target="_blank" class="hover:underline text-blue-400 hover:text-blue-300">Apprise API</a> running or an api that will handle those same requests. <br />The Apprise API Url should be the full URL path to send the notification, e.g., if your API instance is served at
|
||||||
<span class="rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono">http://192.168.1.1:8337</span> then you would put <span class="rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono">http://192.168.1.1:8337/notify</span>.
|
<span class="rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono">http://192.168.1.1:8337</span> then you would put <span class="rounded-md bg-neutral-600 text-sm text-white py-0.5 px-1 font-mono">http://192.168.1.1:8337/notify</span>.
|
||||||
@ -13,33 +13,33 @@
|
|||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-text-input ref="maxNotificationQueueInput" type="number" v-model="maxNotificationQueue" no-spinner :disabled="savingSettings" :padding-x="1" text-center class="w-10" />
|
<ui-text-input ref="maxNotificationQueueInput" type="number" v-model="maxNotificationQueue" no-spinner :disabled="savingSettings" :padding-x="1" text-center class="w-10" />
|
||||||
|
|
||||||
<ui-tooltip text="Events are limited to firing 1 per second. Events will be ignored if the queue is at max size. This prevents notification spamming." direction="right">
|
<ui-tooltip :text="$strings.LabelNotificationsMaxQueueSizeHelp" direction="right">
|
||||||
<p class="pl-2 md:pl-4 text-base md:text-lg">Max queue size for notification events<span class="material-icons icon-text ml-1">info_outlined</span></p>
|
<p class="pl-2 md:pl-4 text-base md:text-lg">{{ $strings.LabelNotificationsMaxQueueSize }}<span class="material-icons icon-text ml-1">info_outlined</span></p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center py-2">
|
<div class="flex items-center py-2">
|
||||||
<ui-text-input ref="maxFailedAttemptsInput" type="number" v-model="maxFailedAttempts" no-spinner :disabled="savingSettings" :padding-x="1" text-center class="w-10" />
|
<ui-text-input ref="maxFailedAttemptsInput" type="number" v-model="maxFailedAttempts" no-spinner :disabled="savingSettings" :padding-x="1" text-center class="w-10" />
|
||||||
|
|
||||||
<ui-tooltip text="Notifications are disabled once they fail to send this many times." direction="right">
|
<ui-tooltip :text="$strings.LabelNotificationsMaxFailedAttemptsHelp" direction="right">
|
||||||
<p class="pl-2 md:pl-4 text-base md:text-lg">Max failed attempts<span class="material-icons icon-text ml-1">info_outlined</span></p>
|
<p class="pl-2 md:pl-4 text-base md:text-lg">{{ $strings.LabelNotificationsMaxFailedAttempts }}<span class="material-icons icon-text ml-1">info_outlined</span></p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end pt-4">
|
<div class="flex items-center justify-end pt-4">
|
||||||
<ui-btn :loading="savingSettings" type="submit">Save</ui-btn>
|
<ui-btn :loading="savingSettings" type="submit">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="w-full h-px bg-white bg-opacity-10 my-6" />
|
<div class="w-full h-px bg-white bg-opacity-10 my-6" />
|
||||||
|
|
||||||
<div class="flex items-center justify-between mb-6">
|
<div class="flex items-center justify-between mb-6">
|
||||||
<h2 class="text-xl font-semibold">Notifications</h2>
|
<h2 class="text-xl font-semibold">{{ $strings.HeaderNotifications }}</h2>
|
||||||
<ui-btn small color="success" class="flex items-center" @click="clickCreate">Create <span class="material-icons text-lg pl-2">add</span></ui-btn>
|
<ui-btn small color="success" class="flex items-center" @click="clickCreate">{{ $strings.ButtonCreate }} <span class="material-icons text-lg pl-2">add</span></ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!notifications.length" class="flex justify-center text-center">
|
<div v-if="!notifications.length" class="flex justify-center text-center">
|
||||||
<p class="text-lg text-gray-200">No notifications</p>
|
<p class="text-lg text-gray-200">{{ $strings.MessageNoNotifications }}</p>
|
||||||
</div>
|
</div>
|
||||||
<template v-for="notification in notifications">
|
<template v-for="notification in notifications">
|
||||||
<cards-notification-card :key="notification.id" :notification="notification" @update="updateSettings" @edit="editNotification" />
|
<cards-notification-card :key="notification.id" :notification="notification" @update="updateSettings" @edit="editNotification" />
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
<div class="w-full h-full">
|
<div class="w-full h-full">
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
||||||
<div class="flex items-center mb-2">
|
<div class="flex items-center mb-2">
|
||||||
<h1 class="text-xl">Listening Sessions</h1>
|
<h1 class="text-xl">{{ $strings.HeaderListeningSessions }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end mb-2">
|
<div class="flex justify-end mb-2">
|
||||||
<ui-dropdown v-model="selectedUser" :items="userItems" label="Filter by User" small class="max-w-48" @input="updateUserFilter" />
|
<ui-dropdown v-model="selectedUser" :items="userItems" :label="$strings.LabelFilterByUser" small class="max-w-48" @input="updateUserFilter" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="listeningSessions.length" class="block max-w-full">
|
<div v-if="listeningSessions.length" class="block max-w-full">
|
||||||
<table class="userSessionsTable">
|
<table class="userSessionsTable">
|
||||||
<tr class="bg-primary bg-opacity-40">
|
<tr class="bg-primary bg-opacity-40">
|
||||||
<th class="w-48 min-w-48 text-left">Item</th>
|
<th class="w-48 min-w-48 text-left">{{ $strings.LabelItem }}</th>
|
||||||
<th class="w-20 min-w-20 text-left hidden md:table-cell">User</th>
|
<th class="w-20 min-w-20 text-left hidden md:table-cell">{{ $strings.LabelUser }}</th>
|
||||||
<th class="w-32 min-w-32 text-left hidden md:table-cell">Play Method</th>
|
<th class="w-32 min-w-32 text-left hidden md:table-cell">{{ $strings.LabelPlayMethod }}</th>
|
||||||
<th class="w-32 min-w-32 text-left hidden sm:table-cell">Device Info</th>
|
<th class="w-32 min-w-32 text-left hidden sm:table-cell">{{ $strings.LabelDeviceInfo }}</th>
|
||||||
<th class="w-32 min-w-32">Listened</th>
|
<th class="w-32 min-w-32">{{ $strings.LabelTimeListened }}</th>
|
||||||
<th class="w-16 min-w-16">Last Time</th>
|
<th class="w-16 min-w-16">{{ $strings.LabelLastTime }}</th>
|
||||||
<th class="flex-grow hidden sm:table-cell">Last Update</th>
|
<th class="flex-grow hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr v-for="session in listeningSessions" :key="session.id" class="cursor-pointer" @click="showSession(session)">
|
<tr v-for="session in listeningSessions" :key="session.id" class="cursor-pointer" @click="showSession(session)">
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
<ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p v-else class="text-white text-opacity-50">No sessions yet...</p>
|
<p v-else class="text-white text-opacity-50">{{ $strings.MessageNoListeningSessions }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<modals-listening-session-modal v-model="showSessionModal" :session="selectedSession" @removedSession="removedSession" />
|
<modals-listening-session-modal v-model="showSessionModal" :session="selectedSession" @removedSession="removedSession" />
|
||||||
@ -134,7 +134,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
message: `Start playback for "${session.displayTitle}" at ${this.$secondsToTimestamp(session.currentTime)}?`,
|
message: this.$getString('MessageStartPlaybackAtTime', [session.displayTitle, this.$secondsToTimestamp(session.currentTime)]),
|
||||||
callback: (confirmed) => {
|
callback: (confirmed) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$eventBus.$emit('play-item', {
|
this.$eventBus.$emit('play-item', {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
<div class="bg-bg rounded-md shadow-lg border border-white border-opacity-5 p-4 mb-8">
|
||||||
<h1 class="text-xl">Stats for {{ username }}</h1>
|
<h1 class="text-xl">{{ $strings.HeaderYourStats }}</h1>
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="flex p-2">
|
<div class="flex p-2">
|
||||||
@ -12,7 +12,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ userItemsFinished.length }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ userItemsFinished.length }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Items Finished</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsItemsFinished }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalDaysListened }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalDaysListened }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Days Listened</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsDaysListened }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalMinutesListening }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ totalMinutesListening }}</p>
|
||||||
<p class="font-book text-xs md:text-sm text-white text-opacity-80">Minutes Listening</p>
|
<p class="font-book text-xs md:text-sm text-white text-opacity-80">{{ $strings.LabelStatsMinutesListening }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,11 +40,11 @@
|
|||||||
<stats-daily-listening-chart :listening-stats="listeningStats" class="origin-top-left transform scale-75 lg:scale-100" />
|
<stats-daily-listening-chart :listening-stats="listeningStats" class="origin-top-left transform scale-75 lg:scale-100" />
|
||||||
<div class="w-80 my-6 mx-auto">
|
<div class="w-80 my-6 mx-auto">
|
||||||
<div class="flex mb-4 items-center">
|
<div class="flex mb-4 items-center">
|
||||||
<h1 class="text-2xl font-book">Recent Sessions</h1>
|
<h1 class="text-2xl font-book">{{ $strings.HeaderStatsRecentSessions }}</h1>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn :to="`/config/users/${user.id}/sessions`" class="text-xs" :padding-x="1.5" :padding-y="1">View All</ui-btn>
|
<ui-btn :to="`/config/users/${user.id}/sessions`" class="text-xs" :padding-x="1.5" :padding-y="1">{{ $strings.ButtonViewAll }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="!mostRecentListeningSessions.length">No Listening Sessions</p>
|
<p v-if="!mostRecentListeningSessions.length">{{ $strings.MessageNoListeningSessions }}</p>
|
||||||
<template v-for="(item, index) in mostRecentListeningSessions">
|
<template v-for="(item, index) in mostRecentListeningSessions">
|
||||||
<div :key="item.id" class="w-full py-0.5">
|
<div :key="item.id" class="w-full py-0.5">
|
||||||
<div class="flex items-center mb-1">
|
<div class="flex items-center mb-1">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="h-10 w-10 flex items-center justify-center">
|
<div class="h-10 w-10 flex items-center justify-center">
|
||||||
<span class="material-icons text-2xl">arrow_back</span>
|
<span class="material-icons text-2xl">arrow_back</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="pl-1">All Users</p>
|
<p class="pl-1">{{ $strings.LabelAllUsers }}</p>
|
||||||
</div>
|
</div>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<div class="flex items-center mb-2 mt-4 px-2 sm:px-0">
|
<div class="flex items-center mb-2 mt-4 px-2 sm:px-0">
|
||||||
@ -22,22 +22,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">Listening Stats</h1>
|
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderListeningStats }}</h1>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<p class="text-sm text-gray-300">{{ listeningSessions.length }} Listening Sessions</p>
|
<p class="text-sm text-gray-300">{{ listeningSessions.length }} {{ $strings.HeaderListeningSessions }}</p>
|
||||||
<ui-btn :to="`/config/users/${user.id}/sessions`" class="text-xs mx-2" :padding-x="1.5" :padding-y="1">View All</ui-btn>
|
<ui-btn :to="`/config/users/${user.id}/sessions`" class="text-xs mx-2" :padding-x="1.5" :padding-y="1">{{ $strings.ButtonViewAll }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-300">
|
<p class="text-sm text-gray-300">
|
||||||
Total Time Listened:
|
{{ $strings.LabelTotalTimeListened }}:
|
||||||
<span class="font-mono text-base">{{ listeningTimePretty }}</span>
|
<span class="font-mono text-base">{{ listeningTimePretty }}</span>
|
||||||
</p>
|
</p>
|
||||||
<p v-if="timeListenedToday" class="text-sm text-gray-300">
|
<p v-if="timeListenedToday" class="text-sm text-gray-300">
|
||||||
Time Listened Today:
|
{{ $strings.LabelTimeListenedToday }}:
|
||||||
<span class="font-mono text-base">{{ $elapsedPrettyExtended(timeListenedToday) }}</span>
|
<span class="font-mono text-base">{{ $elapsedPrettyExtended(timeListenedToday) }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div v-if="latestSession" class="mt-4">
|
<div v-if="latestSession" class="mt-4">
|
||||||
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">Last Listening Session</h1>
|
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderLastListeningSession }}</h1>
|
||||||
<p class="text-sm text-gray-300">
|
<p class="text-sm text-gray-300">
|
||||||
<strong>{{ latestSession.displayTitle }}</strong> {{ $dateDistanceFromNow(latestSession.updatedAt) }} for <span class="font-mono text-base">{{ $elapsedPrettyExtended(this.latestSession.timeListening) }}</span>
|
<strong>{{ latestSession.displayTitle }}</strong> {{ $dateDistanceFromNow(latestSession.updatedAt) }} for <span class="font-mono text-base">{{ $elapsedPrettyExtended(this.latestSession.timeListening) }}</span>
|
||||||
</p>
|
</p>
|
||||||
@ -45,21 +45,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">Saved Media Progress</h1>
|
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderSavedMediaProgress }}</h1>
|
||||||
|
|
||||||
<div v-if="mediaProgressWithoutMedia.length" class="flex items-center py-2 mb-2">
|
<div v-if="mediaProgressWithoutMedia.length" class="flex items-center py-2 mb-2">
|
||||||
<p class="text-error">User has media progress for {{ mediaProgressWithoutMedia.length }} items that no longer exist.</p>
|
<p class="text-error">User has media progress for {{ mediaProgressWithoutMedia.length }} items that no longer exist.</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn small :loading="purgingMediaProgress" @click.stop="purgeMediaProgress">Purge Media Progress</ui-btn>
|
<ui-btn small :loading="purgingMediaProgress" @click.stop="purgeMediaProgress">{{ $strings.ButtonPurgeMediaProgress }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table v-if="mediaProgressWithMedia.length" class="userAudiobooksTable">
|
<table v-if="mediaProgressWithMedia.length" class="userAudiobooksTable">
|
||||||
<tr class="bg-primary bg-opacity-40">
|
<tr class="bg-primary bg-opacity-40">
|
||||||
<th class="w-16 text-left">Item</th>
|
<th class="w-16 text-left">{{ $strings.LabelItem }}</th>
|
||||||
<th class="text-left"></th>
|
<th class="text-left"></th>
|
||||||
<th class="w-32">Progress</th>
|
<th class="w-32">{{ $strings.LabelProgress }}</th>
|
||||||
<th class="w-40 hidden sm:table-cell">Started At</th>
|
<th class="w-40 hidden sm:table-cell">{{ $strings.LabelStartedAt }}</th>
|
||||||
<th class="w-40 hidden sm:table-cell">Last Update</th>
|
<th class="w-40 hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="item in mediaProgressWithMedia" :key="item.id" :class="!item.isFinished ? '' : 'isFinished'">
|
<tr v-for="item in mediaProgressWithMedia" :key="item.id" :class="!item.isFinished ? '' : 'isFinished'">
|
||||||
<td>
|
<td>
|
||||||
@ -90,7 +90,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p v-else class="text-white text-opacity-50">Nothing listened to yet...</p>
|
<p v-else class="text-white text-opacity-50">{{ $strings.MessageNoMediaProgress }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="h-10 w-10 flex items-center justify-center">
|
<div class="h-10 w-10 flex items-center justify-center">
|
||||||
<span class="material-icons text-2xl">arrow_back</span>
|
<span class="material-icons text-2xl">arrow_back</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="pl-1">Back to User</p>
|
<p class="pl-1">{{ $strings.LabelBackToUser }}</p>
|
||||||
</div>
|
</div>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<div class="flex items-center mb-2 mt-4 px-2 sm:px-0">
|
<div class="flex items-center mb-2 mt-4 px-2 sm:px-0">
|
||||||
@ -17,16 +17,16 @@
|
|||||||
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
||||||
|
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">Listening Sessions</h1>
|
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderListeningSessions }}</h1>
|
||||||
<div v-if="listeningSessions.length">
|
<div v-if="listeningSessions.length">
|
||||||
<table class="userSessionsTable">
|
<table class="userSessionsTable">
|
||||||
<tr class="bg-primary bg-opacity-40">
|
<tr class="bg-primary bg-opacity-40">
|
||||||
<th class="w-48 min-w-48 text-left">Item</th>
|
<th class="w-48 min-w-48 text-left">{{ $strings.LabelItem }}</th>
|
||||||
<th class="w-32 min-w-32 text-left hidden md:table-cell">Play Method</th>
|
<th class="w-32 min-w-32 text-left hidden md:table-cell">{{ $strings.LabelPlayMethod }}</th>
|
||||||
<th class="w-32 min-w-32 text-left hidden sm:table-cell">Device Info</th>
|
<th class="w-32 min-w-32 text-left hidden sm:table-cell">{{ $strings.LabelDeviceInfo }}</th>
|
||||||
<th class="w-32 min-w-32">Listened</th>
|
<th class="w-32 min-w-32">{{ $strings.LabelTimeListened }}</th>
|
||||||
<th class="w-16 min-w-16">Last Time</th>
|
<th class="w-16 min-w-16">{{ $strings.LabelLastTime }}</th>
|
||||||
<th class="flex-grow hidden sm:table-cell">Last Update</th>
|
<th class="flex-grow hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="session in listeningSessions" :key="session.id" class="cursor-pointer" @click="showSession(session)">
|
<tr v-for="session in listeningSessions" :key="session.id" class="cursor-pointer" @click="showSession(session)">
|
||||||
<td class="py-1 max-w-48">
|
<td class="py-1 max-w-48">
|
||||||
@ -121,7 +121,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
message: `Start playback for "${session.displayTitle}" at ${this.$secondsToTimestamp(session.currentTime)}?`,
|
message: this.$getString('MessageStartPlaybackAtTime', [session.displayTitle, this.$secondsToTimestamp(session.currentTime)]),
|
||||||
callback: (confirmed) => {
|
callback: (confirmed) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$eventBus.$emit('play-item', {
|
this.$eventBus.$emit('play-item', {
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
<!-- Library & folder picker -->
|
<!-- Library & folder picker -->
|
||||||
<div class="flex my-6 -mx-2">
|
<div class="flex my-6 -mx-2">
|
||||||
<div class="w-1/5 px-2">
|
<div class="w-1/5 px-2">
|
||||||
<ui-dropdown v-model="selectedLibraryId" :items="libraryItems" label="Library" :disabled="!!items.length" @input="libraryChanged" />
|
<ui-dropdown v-model="selectedLibraryId" :items="libraryItems" :label="$strings.LabelLibrary" :disabled="!!items.length" @input="libraryChanged" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-3/5 px-2">
|
<div class="w-3/5 px-2">
|
||||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="!selectedLibraryId || !!items.length" label="Folder" />
|
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="!selectedLibraryId || !!items.length" :label="$strings.LabelFolder" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/5 px-2">
|
<div class="w-1/5 px-2">
|
||||||
<ui-text-input-with-label :value="selectedLibraryMediaType" readonly label="Media Type" />
|
<ui-text-input-with-label :value="selectedLibraryMediaType" readonly :label="$strings.LabelMediaType" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -20,18 +20,22 @@
|
|||||||
|
|
||||||
<!-- Picker display -->
|
<!-- Picker display -->
|
||||||
<div v-if="!items.length && !ignoredFiles.length" class="w-full mx-auto border border-white border-opacity-20 px-12 pt-12 pb-4 my-12 relative" :class="isDragging ? 'bg-primary bg-opacity-40' : 'border-dashed'">
|
<div v-if="!items.length && !ignoredFiles.length" class="w-full mx-auto border border-white border-opacity-20 px-12 pt-12 pb-4 my-12 relative" :class="isDragging ? 'bg-primary bg-opacity-40' : 'border-dashed'">
|
||||||
<p class="text-2xl text-center">{{ isDragging ? 'Drop files' : "Drag n' drop files or folders" }}</p>
|
<p class="text-2xl text-center">{{ isDragging ? $strings.LabelUploaderDropFiles : $strings.LabelUploaderDragAndDrop }}</p>
|
||||||
<p class="text-center text-sm my-5">or</p>
|
<p class="text-center text-sm my-5">or</p>
|
||||||
<div class="w-full max-w-xl mx-auto">
|
<div class="w-full max-w-xl mx-auto">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<ui-btn class="w-full mx-1" @click="openFilePicker">Choose files</ui-btn>
|
<ui-btn class="w-full mx-1" @click="openFilePicker">{{ $strings.ButtonChooseFiles }}</ui-btn>
|
||||||
<ui-btn class="w-full mx-1" @click="openFolderPicker">Choose a folder</ui-btn>
|
<ui-btn class="w-full mx-1" @click="openFolderPicker">{{ $strings.ButtonChooseAFolder }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-8 text-center">
|
<div class="pt-8 text-center">
|
||||||
<p class="text-xs text-white text-opacity-50 font-mono mb-4"><strong>Supported File Types: </strong>{{ inputAccept.join(', ') }}</p>
|
<p class="text-xs text-white text-opacity-50 font-mono mb-4">
|
||||||
|
<strong>{{ $strings.LabelSupportedFileTypes }}: </strong>{{ inputAccept.join(', ') }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="text-sm text-white text-opacity-70">Folders with media files will be treated as separate library items. <span v-if="selectedLibraryMediaType === 'book'">If uploading only audio files then each audio file will be treated as a separate audiobook.</span></p>
|
<p class="text-sm text-white text-opacity-70">
|
||||||
|
{{ $strings.NoteUploaderFoldersWithMediaFiles }} <span v-if="selectedLibraryMediaType === 'book'">{{ $strings.NoteUploaderOnlyAudioFiles }}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Item list header -->
|
<!-- Item list header -->
|
||||||
@ -39,18 +43,20 @@
|
|||||||
<p class="text-lg">{{ items.length }} item{{ items.length === 1 ? '' : 's' }}</p>
|
<p class="text-lg">{{ items.length }} item{{ items.length === 1 ? '' : 's' }}</p>
|
||||||
<p v-if="ignoredFiles.length" class="text-lg"> | {{ ignoredFiles.length }} file{{ ignoredFiles.length === 1 ? '' : 's' }} ignored</p>
|
<p v-if="ignoredFiles.length" class="text-lg"> | {{ ignoredFiles.length }} file{{ ignoredFiles.length === 1 ? '' : 's' }} ignored</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn :disabled="processing" small @click="reset">Reset</ui-btn>
|
<ui-btn :disabled="processing" small @click="reset">{{ $strings.ButtonReset }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Alerts -->
|
<!-- Alerts -->
|
||||||
<widgets-alert v-if="!items.length && !uploadReady" type="error" class="my-4">
|
<widgets-alert v-if="!items.length && !uploadReady" type="error" class="my-4">
|
||||||
<p class="text-lg">No items found</p>
|
<p class="text-lg">{{ $strings.MessageNoItemsFound }}</p>
|
||||||
</widgets-alert>
|
</widgets-alert>
|
||||||
<widgets-alert v-if="ignoredFiles.length" type="warning" class="my-4">
|
<widgets-alert v-if="ignoredFiles.length" type="warning" class="my-4">
|
||||||
<div class="w-full pr-12">
|
<div class="w-full pr-12">
|
||||||
<p class="text-base mb-1">Unsupported files are ignored. When choosing or dropping a folder, other files that are not in an item folder are ignored.</p>
|
<p class="text-base mb-1">{{ $strings.NoteUploaderUnsupportedFiles }}</p>
|
||||||
<tables-uploaded-files-table :files="ignoredFiles" title="Ignored Files" class="text-white" />
|
<tables-uploaded-files-table :files="ignoredFiles" :title="$strings.HeaderIgnoredFiles" class="text-white" />
|
||||||
<p class="text-xs text-white text-opacity-50 font-mono pt-1"><strong>Supported File Types: </strong>{{ inputAccept.join(', ') }}</p>
|
<p class="text-xs text-white text-opacity-50 font-mono pt-1">
|
||||||
|
<strong>{{ $strings.LabelSupportedFileTypes }}: </strong>{{ inputAccept.join(', ') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</widgets-alert>
|
</widgets-alert>
|
||||||
|
|
||||||
@ -61,8 +67,8 @@
|
|||||||
|
|
||||||
<!-- Upload/Reset btns -->
|
<!-- Upload/Reset btns -->
|
||||||
<div v-show="items.length" class="flex justify-end pb-8 pt-4">
|
<div v-show="items.length" class="flex justify-end pb-8 pt-4">
|
||||||
<ui-btn v-if="!uploadFinished" color="success" :loading="processing" @click="submit">Upload</ui-btn>
|
<ui-btn v-if="!uploadFinished" color="success" :loading="processing" @click="submit">{{ $strings.ButtonUpload }}</ui-btn>
|
||||||
<ui-btn v-else @click="reset">Reset</ui-btn>
|
<ui-btn v-else @click="reset">{{ $strings.ButtonReset }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,8 +2,25 @@ import Vue from "vue"
|
|||||||
|
|
||||||
const defaultCode = 'en-us'
|
const defaultCode = 'en-us'
|
||||||
|
|
||||||
|
function supplant(str, subs) {
|
||||||
|
// source: http://crockford.com/javascript/remedial.html
|
||||||
|
return str.replace(/{([^{}]*)}/g,
|
||||||
|
function (a, b) {
|
||||||
|
var r = subs[b]
|
||||||
|
return typeof r === 'string' || typeof r === 'number' ? r : a
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Vue.prototype.$i18nCode = ''
|
Vue.prototype.$i18nCode = ''
|
||||||
Vue.prototype.$strings = {}
|
Vue.prototype.$strings = {}
|
||||||
|
Vue.prototype.$getString = (key, subs) => {
|
||||||
|
if (!Vue.prototype.$strings[key]) return ''
|
||||||
|
if (subs && Array.isArray(subs) && subs.length) {
|
||||||
|
return supplant(Vue.prototype.$strings[key], subs)
|
||||||
|
}
|
||||||
|
return Vue.prototype.$strings[key]
|
||||||
|
}
|
||||||
|
|
||||||
var translations = {}
|
var translations = {}
|
||||||
|
|
||||||
|
@ -1,54 +1,314 @@
|
|||||||
{
|
{
|
||||||
"ButtonHome": "Home",
|
"ButtonAdd": "Add",
|
||||||
"ButtonLatest": "Latest",
|
"ButtonAddChapters": "Add Chapters",
|
||||||
"ButtonLibrary": "Library",
|
"ButtonAddYourFirstLibrary": "Add your first library",
|
||||||
"ButtonSeries": "Series",
|
"ButtonApplyChapters": "Apply Chapters",
|
||||||
"ButtonCollections": "Collections",
|
|
||||||
"ButtonAuthors": "Authors",
|
"ButtonAuthors": "Authors",
|
||||||
"ButtonSearch": "Search",
|
"ButtonBrowseForFolder": "Browse for Folder",
|
||||||
"ButtonIssues": "Issues",
|
"ButtonCancel": "Cancel",
|
||||||
"ButtonChangePasswordSubmit": "Submit",
|
"ButtonChangePasswordSubmit": "Submit",
|
||||||
|
"ButtonChangeRootPassword": "Change Root Password",
|
||||||
|
"ButtonChooseAFolder": "Choose a folder",
|
||||||
|
"ButtonChooseFiles": "Choose files",
|
||||||
|
"ButtonCollections": "Collections",
|
||||||
|
"ButtonCreate": "Create",
|
||||||
|
"ButtonCreateBackup": "Create Backup",
|
||||||
|
"ButtonEditChapters": "Edit Chapters",
|
||||||
|
"ButtonForceReScan": "Force Re-Scan",
|
||||||
|
"ButtonFullPath": "Full Path",
|
||||||
|
"ButtonHide": "Hide",
|
||||||
|
"ButtonHome": "Home",
|
||||||
|
"ButtonIssues": "Issues",
|
||||||
|
"ButtonLatest": "Latest",
|
||||||
"ButtonLogout": "Logout",
|
"ButtonLogout": "Logout",
|
||||||
|
"ButtonLookup": "Lookup",
|
||||||
|
"ButtonLibrary": "Library",
|
||||||
|
"ButtonMatchAllAuthors": "Match All Authors",
|
||||||
|
"ButtonMatchBooks": "Match Books",
|
||||||
|
"ButtonMapChapterTitles": "Map Chapter Titles",
|
||||||
|
"ButtonNevermind": "Nevermind",
|
||||||
|
"ButtonOk": "Ok",
|
||||||
|
"ButtonOpenManager": "Open Manager",
|
||||||
"ButtonPurgeAllCache": "Purge All Cache",
|
"ButtonPurgeAllCache": "Purge All Cache",
|
||||||
"ButtonPurgeItemsCache": "Purge Items Cache",
|
"ButtonPurgeItemsCache": "Purge Items Cache",
|
||||||
|
"ButtonPurgeMediaProgress": "Purge Media Progress",
|
||||||
|
"ButtonQuickMatch": "Quick Match",
|
||||||
|
"ButtonRemove": "Remove",
|
||||||
|
"ButtonRemoveAll": "Remove All",
|
||||||
"ButtonRemoveAllLibraryItems": "Remove All Library Items",
|
"ButtonRemoveAllLibraryItems": "Remove All Library Items",
|
||||||
|
"ButtonReScan": "Re-Scan",
|
||||||
|
"ButtonReset": "Reset",
|
||||||
|
"ButtonRestore": "Restore",
|
||||||
|
"ButtonSave": "Save",
|
||||||
|
"ButtonSaveAndClose": "Save & Close",
|
||||||
|
"ButtonScan": "Scan",
|
||||||
|
"ButtonSearch": "Search",
|
||||||
|
"ButtonSelectFolderPath": "Select Folder Path",
|
||||||
|
"ButtonSeries": "Series",
|
||||||
|
"ButtonShiftTimes": "Shift Times",
|
||||||
|
"ButtonShow": "Show",
|
||||||
|
"ButtonSubmit": "Submit",
|
||||||
|
"ButtonUpload": "Upload",
|
||||||
|
"ButtonUploadBackup": "Upload Backup",
|
||||||
|
"ButtonUploadCover": "Upload Cover",
|
||||||
|
"ButtonViewAll": "View All",
|
||||||
|
"ButtonYes": "Yes",
|
||||||
"HeaderAccount": "Account",
|
"HeaderAccount": "Account",
|
||||||
"HeaderChangePassword": "Change Password",
|
"HeaderAdvanced": "Advanced",
|
||||||
"HeaderSettings": "Settings",
|
"HeaderAppriseNotificationSettings": "Apprise Notification Settings",
|
||||||
"HeaderLibraries": "Libraries",
|
"HeaderAudiobookTools": "Audiobook File Management Tools",
|
||||||
"HeaderUsers": "Users",
|
"HeaderAudioTracks": "Audio Tracks",
|
||||||
"HeaderListeningSessions": "Listening Sessions",
|
|
||||||
"HeaderBackups": "Backups",
|
"HeaderBackups": "Backups",
|
||||||
"HeaderLogs": "Logs",
|
"HeaderChangePassword": "Change Password",
|
||||||
"HeaderNotifications": "Notifications",
|
"HeaderChapters": "Chapters",
|
||||||
|
"HeaderChooseAFolder": "Choose a Folder",
|
||||||
|
"HeaderCollection": "Collection",
|
||||||
|
"HeaderCover": "Cover",
|
||||||
|
"HeaderDetails": "Details",
|
||||||
|
"HeaderEpisodes": "Episodes",
|
||||||
|
"HeaderFiles": "Files",
|
||||||
|
"HeaderFindChapters": "Find Chapters",
|
||||||
|
"HeaderIgnoredFiles": "Ignored Files",
|
||||||
|
"HeaderItemFiles": "Item Files",
|
||||||
|
"HeaderLastListeningSession": "Last Listening Session",
|
||||||
|
"HeaderLibraries": "Libraries",
|
||||||
|
"HeaderLibraryFiles": "Library Files",
|
||||||
"HeaderLibraryStats": "Library Stats",
|
"HeaderLibraryStats": "Library Stats",
|
||||||
"HeaderYourStats": "Your Stats",
|
"HeaderListeningSessions": "Listening Sessions",
|
||||||
"HeaderSettingsGeneral": "General",
|
"HeaderListeningStats": "Listening Stats",
|
||||||
"HeaderSettingsScanner": "Scanner",
|
"HeaderLogs": "Logs",
|
||||||
|
"HeaderMatch": "Match",
|
||||||
|
"HeaderNewAccount": "New Account",
|
||||||
|
"HeaderNewLibrary": "New Library",
|
||||||
|
"HeaderNotifications": "Notifications",
|
||||||
|
"HeaderOtherFiles": "Other Files",
|
||||||
|
"HeaderPermissions": "Permissions",
|
||||||
|
"HeaderPreviewCover": "Preview Cover",
|
||||||
|
"HeaderSavedMediaProgress": "Saved Media Progress",
|
||||||
|
"HeaderSchedule": "Schedule",
|
||||||
|
"HeaderScheduleLibraryScans": "Schedule Automatic Library Scans",
|
||||||
|
"HeaderSettings": "Settings",
|
||||||
"HeaderSettingsDisplay": "Display",
|
"HeaderSettingsDisplay": "Display",
|
||||||
"HeaderSettingsExperimental": "Experimental Features",
|
"HeaderSettingsExperimental": "Experimental Features",
|
||||||
"LabelUsername": "Username",
|
"HeaderSettingsGeneral": "General",
|
||||||
|
"HeaderSettingsScanner": "Scanner",
|
||||||
|
"HeaderStatsLongestItems": "Longest Items (hrs)",
|
||||||
|
"HeaderStatsMinutesListeningChart": "Minutes Listening (last 7 days)",
|
||||||
|
"HeaderStatsRecentSessions": "Recent Sessions",
|
||||||
|
"HeaderStatsTop10Authors": "Top 10 Authors",
|
||||||
|
"HeaderStatsTop5Genres": "Top 5 Genres",
|
||||||
|
"HeaderTools": "Tools",
|
||||||
|
"HeaderUpdateAccount": "Update Account",
|
||||||
|
"HeaderUpdateDetails": "Update Details",
|
||||||
|
"HeaderUpdateLibrary": "Update Library",
|
||||||
|
"HeaderUsers": "Users",
|
||||||
|
"HeaderYourStats": "Your Stats",
|
||||||
"LabelAccountType": "Account Type",
|
"LabelAccountType": "Account Type",
|
||||||
"LabelPassword": "Password",
|
"LabelActivity": "Activity",
|
||||||
"LabelNewPassword": "New Password",
|
"LabelAllUsers": "All Users",
|
||||||
|
"LabelAuthor": "Author",
|
||||||
|
"LabelAuthors": "Authors",
|
||||||
|
"LabelBackToUser": "Back to User",
|
||||||
|
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
|
||||||
|
"LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups",
|
||||||
|
"LabelBackupsMaxBackupSize": "Maximum backup size (in GB)",
|
||||||
|
"LabelBackupsMaxBackupSizeHelp": "As a safeguard against misconfiguration, backups will fail if they exceed the configured size.",
|
||||||
|
"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.",
|
||||||
|
"LabelBooks": "Books",
|
||||||
|
"LabelChangePassword": "Change Password",
|
||||||
|
"LabelCollapseSeries": "Collapse Series",
|
||||||
|
"LabelCollections": "Collections",
|
||||||
"LabelConfirmPassword": "Confirm Password",
|
"LabelConfirmPassword": "Confirm Password",
|
||||||
|
"LabelCover": "Cover",
|
||||||
|
"LabelCoverImageURL": "Cover Image URL",
|
||||||
|
"LabelCreatedAt": "Created At",
|
||||||
|
"LabelCronExpression": "Cron Expression",
|
||||||
|
"LabelCurrently": "Currently:",
|
||||||
|
"LabelDatetime": "Datetime",
|
||||||
|
"LabelDescription": "Description",
|
||||||
|
"LabelDeviceInfo": "Device Info",
|
||||||
|
"LabelDirectory": "Directory",
|
||||||
|
"LabelDownload": "Download",
|
||||||
|
"LabelDuration": "Duration",
|
||||||
|
"LabelEnable": "Enable",
|
||||||
|
"LabelEnd": "End",
|
||||||
|
"LabelExplicit": "Explicit",
|
||||||
|
"LabelFile": "File",
|
||||||
|
"LabelFilename": "Filename",
|
||||||
|
"LabelFilterByUser": "Filter by User",
|
||||||
|
"LabelFinished": "Finished",
|
||||||
|
"LabelFolder": "Folder",
|
||||||
|
"LabelFolders": "Folders",
|
||||||
|
"LabelGenres": "Genres",
|
||||||
|
"LabelHour": "Hour",
|
||||||
|
"LabelIcon": "Icon",
|
||||||
|
"LabelInterval": "Interval",
|
||||||
|
"LabelItem": "Item",
|
||||||
|
"LabelLanguage": "Language",
|
||||||
|
"LabelLastSeen": "Last Seen",
|
||||||
|
"LabelLastTime": "Last Time",
|
||||||
|
"LabelLastUpdate": "Last Update",
|
||||||
|
"LabelLibrariesAccessibleToUser": "Libraries Accessible to User",
|
||||||
|
"LabelLibrary": "Library",
|
||||||
|
"LabelLibraryName": "Library Name",
|
||||||
|
"LabelMarkSeries": "Mark Series",
|
||||||
|
"LabelMediaType": "Media Type",
|
||||||
|
"LabelMetadataProvider": "Metadata Provider",
|
||||||
|
"LabelMinute": "Minute",
|
||||||
|
"LabelName": "Name",
|
||||||
|
"LabelNarrators": "Narrators",
|
||||||
|
"LabelNewPassword": "New Password",
|
||||||
|
"LabelNotFinished": "Not Finished",
|
||||||
|
"LabelNotificationEvent": "Notification Event",
|
||||||
|
"LabelNotificationAppriseURL": "Apprise URL(s)",
|
||||||
|
"LabelNotificationAvailableVariables": "Available variables",
|
||||||
|
"LabelNotificationBodyTemplate": "Body Template",
|
||||||
|
"LabelNotificationTitleTemplate": "Title Template",
|
||||||
|
"LabelNotificationsMaxFailedAttempts": "Max failed attempts",
|
||||||
|
"LabelNotificationsMaxFailedAttemptsHelp": "Notifications are disabled once they fail to send this many times",
|
||||||
|
"LabelNotificationsMaxQueueSize": "Max queue size for notification events",
|
||||||
|
"LabelNotificationsMaxQueueSizeHelp": "Events are limited to firing 1 per second. Events will be ignored if the queue is at max size. This prevents notification spamming.",
|
||||||
|
"LabelPassword": "Password",
|
||||||
|
"LabelPath": "Path",
|
||||||
|
"LabelPermissionsAccessAllLibraries": "Can Access All Libraries",
|
||||||
|
"LabelPermissionsAccessAllTags": "Can Access All Tags",
|
||||||
|
"LabelPermissionsAccessExplicitContent": "Can Access Explicit Content",
|
||||||
|
"LabelPermissionsDelete": "Can Delete",
|
||||||
|
"LabelPermissionsDownload": "Can Download",
|
||||||
|
"LabelPermissionsUpdate": "Can Update",
|
||||||
|
"LabelPermissionsUpload": "Can Upload",
|
||||||
|
"LabelPlayMethod": "Play Method",
|
||||||
|
"LabelPodcasts": "Podcasts",
|
||||||
|
"LabelPrefixesToIgnore": "Prefixes to Ignore (case insensitive)",
|
||||||
|
"LabelProgress": "Progress",
|
||||||
|
"LabelProvider": "Provider",
|
||||||
|
"LabelPublisher": "Publisher",
|
||||||
|
"LabelPublishYear": "Publish Year",
|
||||||
|
"LabelRegion": "Region",
|
||||||
|
"LabelReleaseDate": "Release Date",
|
||||||
|
"LabelSearchTerm": "Search Term",
|
||||||
|
"LabelSearchTitle": "Search Title",
|
||||||
|
"LabelSearchTitleOrASIN": "Search Title or ASIN",
|
||||||
|
"LabelSequence": "Sequence",
|
||||||
|
"LabelSeries": "Series",
|
||||||
|
"LabelSeriesName": "Series Name",
|
||||||
|
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
|
||||||
|
"LabelSettingsChromecastSupport": "Chromecast support",
|
||||||
|
"LabelSettingsDateFormat": "Date Format",
|
||||||
|
"LabelSettingsDisableWatcher": "Disable Watcher",
|
||||||
|
"LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library",
|
||||||
|
"LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart",
|
||||||
|
"LabelSettingsEnableEReader": "Enable e-reader for all users",
|
||||||
|
"LabelSettingsEnableEReaderHelp": "E-reader is still a work in progress, but use this setting to open it up to all your users (or use the \"Experimental Features\" toggle just for use by you)",
|
||||||
|
"LabelSettingsExperimentalFeatures": "Experimental features",
|
||||||
|
"LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
|
||||||
|
"LabelSettingsFindCovers": "Find covers",
|
||||||
|
"LabelSettingsFindCoversHelp": "If your audiobook does not have an embedded cover or a cover image inside the folder, the scanner will attempt to find a cover.<br>Note: This will extend scan time",
|
||||||
|
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
||||||
|
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
||||||
|
"LabelSettingsOverdriveMediaMarkers": "Use Overdrive Media Markers for chapters",
|
||||||
|
"LabelSettingsOverdriveMediaMarkersHelp": "MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically",
|
||||||
|
"LabelSettingsParseSubtitles": "Parse subtitles",
|
||||||
|
"LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"",
|
||||||
|
"LabelSettingsPreferAudioMetadata": "Prefer audio metadata",
|
||||||
|
"LabelSettingsPreferAudioMetadataHelp": "Audio file ID3 meta tags will be used for book details over folder names",
|
||||||
|
"LabelSettingsPreferMatchedMetadata": "Prefer matched metadata",
|
||||||
|
"LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.",
|
||||||
|
"LabelSettingsPreferOPFMetadata": "Prefer OPF metadata",
|
||||||
|
"LabelSettingsPreferOPFMetadataHelp": "OPF file metadata will be used for book details over folder names",
|
||||||
|
"LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN",
|
||||||
|
"LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN",
|
||||||
|
"LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting",
|
||||||
|
"LabelSettingsSortingIgnorePrefixesHelp": "i.e. for prefix \"the\" book title \"The Book Title\" would sort as \"Book Title, The\"",
|
||||||
"LabelSettingsStoreCoversWithItem": "Store covers with item",
|
"LabelSettingsStoreCoversWithItem": "Store covers with item",
|
||||||
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
|
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
|
||||||
"LabelSettingsStoreMetadataWithItem": "Store metadata with item",
|
"LabelSettingsStoreMetadataWithItem": "Store metadata with item",
|
||||||
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension",
|
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension",
|
||||||
"LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting",
|
"LabelSettingsSquareBookCovers": "User square book covers",
|
||||||
"LabelSettingsSortingIgnorePrefixesHelp": "i.e. for prefix \"the\" book title \"The Book Title\" would sort as \"Book Title, The\"",
|
"LabelSettingsSquareBookCoversHelp": "Prefer to use square covers over standard 1.6:1 book covers",
|
||||||
"LabelPrefixesToIgnore": "Prefixes to Ignore (case insensitive)",
|
"LabelSize": "Size",
|
||||||
"LabelSettingsChromecastSupport": "Chromecast support",
|
"LabelStart": "Start",
|
||||||
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
"LabelStartedAt": "Started At",
|
||||||
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
"LabelStatsAudioTracks": "Audio Tracks",
|
||||||
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
|
"LabelStatsAuthors": "Authors",
|
||||||
"LabelSettingsDateFormat": "Date Format",
|
"LabelStatsBestDay": "Best Day",
|
||||||
"LabelSettingsParseSubtitles": "Parse subtitles",
|
"LabelStatsDailyAverage": "Daily Average",
|
||||||
"LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"",
|
"LabelStatsDays": "Days",
|
||||||
"LabelSettingsFindCovers": "Find covers",
|
"LabelStatsDaysListened": "Days Listened",
|
||||||
"LabelSettingsFindCoversHelp": "If your audiobook does not have an embedded cover or a cover image inside the folder, the scanner will attempt to find a cover.<br>Note: This will extend scan time",
|
"LabelStatsHours": "Hours",
|
||||||
|
"LabelStatsInARow": "in a row",
|
||||||
|
"LabelStatsItemsFinished": "Items Finished",
|
||||||
|
"LabelStatsItemsInLibrary": "Items in Library",
|
||||||
|
"LabelStatsMinutes": "minutes",
|
||||||
|
"LabelStatsMinutesListening": "Minutes Listening",
|
||||||
|
"LabelStatsOverall": "Overall",
|
||||||
|
"LabelStatsWeekListening": "Week Listening",
|
||||||
|
"LabelSubtitle": "Subtitle",
|
||||||
|
"LabelSupportedFileTypes": "Supported File Types",
|
||||||
|
"LabelTags": "Tags",
|
||||||
|
"LabelTagsAccessibleToUser": "Tags Accessible to User",
|
||||||
|
"LabelTimeListened": "Time Listened",
|
||||||
|
"LabelTimeListenedToday": "Time Listened Today",
|
||||||
|
"LabelTimeToShift": "Time to shift in seconds",
|
||||||
|
"LabelTitle": "Title",
|
||||||
|
"LabelTotalTimeListened": "Total Time Listened",
|
||||||
|
"LabelType": "Type",
|
||||||
|
"LabelUploaderDragAndDrop": "Drag & drop files or folders",
|
||||||
|
"LabelUploaderDropFiles": "Drop files",
|
||||||
|
"LabelUser": "User",
|
||||||
|
"LabelUsername": "Username",
|
||||||
|
"LabelWeekdaysToRun": "Weekdays to run",
|
||||||
|
"MessageBackupsDescription": "Backups include users, user progress, library item details, server settings, and images stored in",
|
||||||
|
"MessageBackupsNote": "Backups do not include any files stored in your library folders.",
|
||||||
|
"MessageCheckingCron": "Checking cron...",
|
||||||
|
"MessageForceReScanDescription": "will scan all files again like a fresh scan. Audio file ID3 tags, OPF files, and text files will be scanned as new.",
|
||||||
|
"MessageImportantNotice": "Important Notice!",
|
||||||
|
"MessageInsertChapterBelow": "Insert chapter below",
|
||||||
|
"MessageJoinUsOn": "Join us on",
|
||||||
|
"MessageLoading": "Loading...",
|
||||||
|
"MessageLoadingFolders": "Loading folders...",
|
||||||
|
"MessageMapChapterTitles": "Map chapter titles to your existing audiobook chapters without adjusting timestamps",
|
||||||
|
"MessageMatchBooksDescription": "will attempt to match books in the library with a book from the selected search provider and fill in empty details and cover art. Does not overwrite details.",
|
||||||
|
"MessageNoAuthors": "No Authors",
|
||||||
|
"MessageNoChapters": "No Chapters",
|
||||||
|
"MessageNoCoversFound": "No Covers Found",
|
||||||
|
"MessageNoFoldersAvailable": "No Folders Available",
|
||||||
|
"MessageNoGenres": "No Genres",
|
||||||
|
"MessageNoItems": "No Items",
|
||||||
|
"MessageNoItemsFound": "No items found",
|
||||||
|
"MessageNoListeningSessions": "No Listening Sessions",
|
||||||
|
"MessageNoLogs": "No Logs",
|
||||||
|
"MessageNoMediaProgress": "No Media Progress",
|
||||||
|
"MessageNoNotifications": "No Notifications",
|
||||||
|
"MessageNoResults": "No Results",
|
||||||
|
"MessageQuickMatchDescription": "Populate empty item details & cover with first match result from '{0}'. Does not overwrite details unless 'Prefer matched metadata' server setting is enabled.",
|
||||||
|
"MessageRemoveAllItemsWarning": "WARNING! This action will remove all library items from the database including any updates or matches you have made. This does not do anything to your actual files. Are you sure?",
|
||||||
|
"MessageRemoveUserWarning": "Are you sure you want to permanently delete user \"{0}\"?",
|
||||||
"MessageReportBugsAndContribute": "Report bugs, request features, and contribute on",
|
"MessageReportBugsAndContribute": "Report bugs, request features, and contribute on",
|
||||||
|
"MessageRestoreBackupConfirm": "Are you sure you want to restore the backup created on",
|
||||||
|
"MessageRestoreBackupWarning": "Restoring a backup will overwrite the entire database located at /config and cover images in /metadata/items & /metadata/authors.<br /><br />Backups do not modify any files in your library folders. If you have enabled server settings to store cover art and metadata in your library folders then those are not backed up or overwritten.<br /><br />All clients using your server will be automatically refreshed.",
|
||||||
|
"MessageSearchResultsFor": "Search results for",
|
||||||
|
"MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?",
|
||||||
|
"MessageUploaderItemFailed": "Failed to upload",
|
||||||
|
"MessageUploaderItemSuccess": "Successfully Uploaded!",
|
||||||
|
"MessageUploading": "Uploading...",
|
||||||
|
"MessageValidCronExpression": "Valid cron expression",
|
||||||
|
"MessageWatcherIsDisabledGlobally": "Watcher is disabled globally in server settings",
|
||||||
"NoteChangeRootPassword": "Root user is the only user that can have an empty password",
|
"NoteChangeRootPassword": "Root user is the only user that can have an empty password",
|
||||||
"SearchPlaceholder": "Search.."
|
"NoteChapterEditorTimes": "Note: First chapter start time must remain at 0:00 and the last chapter start time cannot exceed this audiobooks duration.",
|
||||||
|
"NoteFolderPicker": "Note: folders already mapped will not be shown",
|
||||||
|
"NoteFolderPickerDebian": "Note: Folder picker for the debian install is not fully implemented. You should enter the path to your library directly.",
|
||||||
|
"NoteUploaderFoldersWithMediaFiles": "Folders with media files will be handled as separate library items.",
|
||||||
|
"NoteUploaderOnlyAudioFiles": "If uploading only audio files then each audio file will be handled as a separate audiobook.",
|
||||||
|
"NoteUploaderUnsupportedFiles": "Unsupported files are ignored. When choosing or dropping a folder, other files that are not in an item folder are ignored.",
|
||||||
|
"PlaceholderNewFolderPath": "New folder path",
|
||||||
|
"PlaceholderSearch": "Search..",
|
||||||
|
"WeekdayFriday": "Friday",
|
||||||
|
"WeekdayMonday": "Monday",
|
||||||
|
"WeekdaySaturday": "Saturday",
|
||||||
|
"WeekdaySunday": "Sunday",
|
||||||
|
"WeekdayThursday": "Thursday",
|
||||||
|
"WeekdayTuesday": "Tuesday",
|
||||||
|
"WeekdayWednesday": "Wednesday"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user