mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-03 17:54:54 +02:00
Update:More localization strings #1103
This commit is contained in:
parent
c1b3d7779b
commit
400e34a4c7
63 changed files with 681 additions and 584 deletions
|
@ -125,20 +125,6 @@ export default {
|
|||
processing: false,
|
||||
newUser: {},
|
||||
isNew: true,
|
||||
accountTypes: [
|
||||
{
|
||||
text: 'Guest',
|
||||
value: 'guest'
|
||||
},
|
||||
{
|
||||
text: 'User',
|
||||
value: 'user'
|
||||
},
|
||||
{
|
||||
text: 'Admin',
|
||||
value: 'admin'
|
||||
}
|
||||
],
|
||||
tags: [],
|
||||
loadingTags: false
|
||||
}
|
||||
|
@ -161,6 +147,22 @@ export default {
|
|||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
accountTypes() {
|
||||
return [
|
||||
{
|
||||
text: this.$strings.LabelAccountTypeGuest,
|
||||
value: 'guest'
|
||||
},
|
||||
{
|
||||
text: this.$strings.LabelAccountTypeUser,
|
||||
value: 'user'
|
||||
},
|
||||
{
|
||||
text: this.$strings.LabelAccountTypeAdmin,
|
||||
value: 'admin'
|
||||
}
|
||||
]
|
||||
},
|
||||
user() {
|
||||
return this.$store.state.user.user
|
||||
},
|
||||
|
@ -249,7 +251,7 @@ export default {
|
|||
.then((data) => {
|
||||
this.processing = false
|
||||
if (data.error) {
|
||||
this.$toast.error(`Failed to update account: ${data.error}`)
|
||||
this.$toast.error(`${this.$strings.ToastAccountUpdateFailed}: ${data.error}`)
|
||||
} else {
|
||||
console.log('Account updated', data.user)
|
||||
|
||||
|
@ -258,7 +260,7 @@ export default {
|
|||
this.$store.commit('user/setUserToken', data.user.token)
|
||||
}
|
||||
|
||||
this.$toast.success('Account updated')
|
||||
this.$toast.success(this.$strings.ToastAccountUpdateSuccess)
|
||||
this.show = false
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
<modals-modal v-model="show" name="backup-scheduler" :width="700" :height="'unset'" :processing="processing">
|
||||
<template #outer>
|
||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||
<p class="font-book text-3xl text-white truncate">Set Backup Schedule</p>
|
||||
<p class="font-book text-3xl text-white truncate">{{ $strings.HeaderSetBackupSchedule }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="show && newCronExpression" 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">
|
||||
<widgets-cron-expression-builder ref="expressionBuilder" v-model="newCronExpression" @input="expressionUpdated" />
|
||||
|
||||
<div class="flex items-center justify-end">
|
||||
<ui-btn :disabled="!isUpdated" @click="submit">{{ isUpdated ? 'Save Backup Schedule' : 'No update necessary' }}</ui-btn>
|
||||
<ui-btn :disabled="!isUpdated" @click="submit">{{ isUpdated ? $strings.ButtonSave : $strings.MessageNoUpdateNecessary }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
|
|
@ -7,40 +7,36 @@
|
|||
</template>
|
||||
|
||||
<div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
|
||||
<div v-if="show" class="w-full h-full">
|
||||
<div class="py-4 px-4">
|
||||
<h1 class="text-2xl">Quick Match {{ selectedBookIds.length }} Books</h1>
|
||||
</div>
|
||||
|
||||
<div v-if="show" class="w-full h-full py-4">
|
||||
<div class="w-full overflow-y-auto overflow-x-hidden max-h-96">
|
||||
<div class="flex px-8 items-center py-2">
|
||||
<p class="pr-4">Provider</p>
|
||||
<p class="pr-4">{{ $strings.LabelProvider }}</p>
|
||||
<ui-dropdown v-model="options.provider" :items="providers" small />
|
||||
</div>
|
||||
<p class="text-base px-8 py-2">Quick Match will attempt to add missing covers and metadata for the selected books. Enable the options below to allow Quick Match to overwrite existing covers and/or metadata.</p>
|
||||
<p class="text-base px-8 py-2">{{ $strings.MessageBatchQuickMatchDescription }}</p>
|
||||
<div class="flex px-8 items-end py-2">
|
||||
<ui-toggle-switch v-model="options.overrideCover"/>
|
||||
<ui-tooltip :text="tooltips.updateCovers">
|
||||
<ui-toggle-switch v-model="options.overrideCover" />
|
||||
<ui-tooltip :text="$strings.LabelUpdateCoverHelp">
|
||||
<p class="pl-4">
|
||||
Update Covers
|
||||
{{ $strings.LabelUpdateCover }}
|
||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div class="flex px-8 items-end py-2">
|
||||
<ui-toggle-switch v-model="options.overrideDetails"/>
|
||||
<ui-tooltip :text="tooltips.updateDetails">
|
||||
<ui-toggle-switch v-model="options.overrideDetails" />
|
||||
<ui-tooltip :text="$strings.LabelUpdateDetailsHelp">
|
||||
<p class="pl-4">
|
||||
Update Details
|
||||
{{ $strings.LabelUpdateDetails }}
|
||||
<span class="material-icons icon-text text-sm">info_outlined</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div class="mt-4 py-4 border-b border-white border-opacity-10 text-white text-opacity-80 border-t border-white border-opacity-5">
|
||||
<div class="mt-4 pt-4 text-white text-opacity-80 border-t border-white border-opacity-5">
|
||||
<div class="flex items-center px-4">
|
||||
<ui-btn type="button" @click="show = false">Cancel</ui-btn>
|
||||
<ui-btn type="button" @click="show = false">{{ $strings.ButtonCancel }}</ui-btn>
|
||||
<div class="flex-grow" />
|
||||
<ui-btn color="success" @click="doBatchQuickMatch">Continue</ui-btn>
|
||||
<ui-btn color="success" @click="doBatchQuickMatch">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -60,10 +56,6 @@ export default {
|
|||
overrideDetails: true,
|
||||
overrideCover: true,
|
||||
overrideDefaults: true
|
||||
},
|
||||
tooltips: {
|
||||
updateCovers: 'Allow overwriting of existing covers for the selected books when a match is located.',
|
||||
updateDetails: 'Allow overwriting of existing details for the selected books when a match is located.'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -84,7 +76,7 @@ export default {
|
|||
}
|
||||
},
|
||||
title() {
|
||||
return `${this.selectedBookIds.length} Items Selected`
|
||||
return this.$getString('MessageItemsSelected', [this.selectedBookIds.length])
|
||||
},
|
||||
showBatchQuickMatchModal() {
|
||||
return this.$store.state.globals.showBatchQuickMatchModal
|
||||
|
@ -107,7 +99,7 @@ export default {
|
|||
init() {
|
||||
// If we don't have a set provider (first open of dialog) or we've switched library, set
|
||||
// the selected provider to the current library default provider
|
||||
if (!this.options.provider || (this.options.lastUsedLibrary != this.currentLibraryId)) {
|
||||
if (!this.options.provider || this.options.lastUsedLibrary != this.currentLibraryId) {
|
||||
this.options.lastUsedLibrary = this.currentLibraryId
|
||||
this.options.provider = this.libraryProvider
|
||||
}
|
||||
|
@ -115,7 +107,7 @@ export default {
|
|||
doBatchQuickMatch() {
|
||||
if (!this.selectedBookIds.length) return
|
||||
if (this.processing) return
|
||||
|
||||
|
||||
this.processing = true
|
||||
this.$store.commit('setProcessingBatch', true)
|
||||
this.$axios
|
||||
|
@ -125,10 +117,12 @@ export default {
|
|||
})
|
||||
.then(() => {
|
||||
this.$toast.info('Batch quick match of ' + this.selectedBookIds.length + ' books started!')
|
||||
}).catch((error) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error('Batch quick match failed')
|
||||
console.error('Failed to batch quick match', error)
|
||||
}).finally(() => {
|
||||
})
|
||||
.finally(() => {
|
||||
this.processing = false
|
||||
this.$store.commit('setProcessingBatch', false)
|
||||
this.show = false
|
||||
|
|
|
@ -85,10 +85,10 @@ export default {
|
|||
this.$axios
|
||||
.$delete(`/api/me/item/${this.libraryItemId}/bookmark/${bm.time}`)
|
||||
.then(() => {
|
||||
this.$toast.success('Bookmark removed')
|
||||
this.$toast.success(this.$strings.ToastBookmarkRemoveSuccess)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(`Failed to remove bookmark`)
|
||||
this.$toast.error(this.$strings.ToastBookmarkRemoveFailed)
|
||||
console.error(error)
|
||||
})
|
||||
this.show = false
|
||||
|
@ -101,10 +101,10 @@ export default {
|
|||
this.$axios
|
||||
.$patch(`/api/me/item/${this.libraryItemId}/bookmark`, bookmark)
|
||||
.then(() => {
|
||||
this.$toast.success('Bookmark updated')
|
||||
this.$toast.success(this.$strings.ToastBookmarkUpdateSuccess)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(`Failed to update bookmark`)
|
||||
this.$toast.error(this.$strings.ToastBookmarkUpdateFailed)
|
||||
console.error(error)
|
||||
})
|
||||
this.show = false
|
||||
|
@ -120,10 +120,10 @@ export default {
|
|||
this.$axios
|
||||
.$post(`/api/me/item/${this.libraryItemId}/bookmark`, bookmark)
|
||||
.then(() => {
|
||||
this.$toast.success('Bookmark added')
|
||||
this.$toast.success(this.$strings.ToastBookmarkCreateSuccess)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(`Failed to create bookmark`)
|
||||
this.$toast.error(this.$strings.ToastBookmarkCreateFailed)
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
|
|
|
@ -96,20 +96,19 @@ export default {
|
|||
this.newCollectionDescription = this.collection.description || ''
|
||||
},
|
||||
removeClick() {
|
||||
if (confirm(`Are you sure you want to remove collection "${this.collectionName}"?`)) {
|
||||
if (confirm(this.$getString('MessageConfirmRemoveCollection', [this.collectionName]))) {
|
||||
this.processing = true
|
||||
var collectionName = this.collectionName
|
||||
this.$axios
|
||||
.$delete(`/api/collections/${this.collection.id}`)
|
||||
.then(() => {
|
||||
this.processing = false
|
||||
this.show = false
|
||||
this.$toast.success(`Collection "${collectionName}" Removed`)
|
||||
this.$toast.success(this.$strings.ToastCollectionRemoveSuccess)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to remove collection', error)
|
||||
this.processing = false
|
||||
this.$toast.error(`Failed to remove collection`)
|
||||
this.$toast.error(this.$strings.ToastCollectionRemoveFailed)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
@ -133,12 +132,12 @@ export default {
|
|||
console.log('Collection Updated', collection)
|
||||
this.processing = false
|
||||
this.show = false
|
||||
this.$toast.success(`Collection "${collection.name}" Updated`)
|
||||
this.$toast.success(this.$strings.ToastCollectionUpdateSuccess)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to update collection', error)
|
||||
this.processing = false
|
||||
this.$toast.error(`Failed to update collection`)
|
||||
this.$toast.error(this.$strings.ToastCollectionUpdateFailed)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<modals-modal v-model="show" name="listening-session-modal" :processing="processing" :width="700" :height="'unset'">
|
||||
<template #outer>
|
||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||
<p class="font-book text-3xl text-white truncate">Session {{ _session.id }}</p>
|
||||
<p class="font-book text-3xl text-white truncate">{{ $strings.HeaderSession }} {{ _session.id }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<div ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden p-6" style="max-height: 80vh">
|
||||
|
@ -15,90 +15,90 @@
|
|||
|
||||
<div class="flex flex-wrap mb-4">
|
||||
<div class="w-full md:w-2/3">
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mb-2">Details</p>
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mb-2">{{ $strings.HeaderDetails }}</p>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Started At</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelStartedAt }}</div>
|
||||
<div class="px-1">
|
||||
{{ $formatDate(_session.startedAt, 'MMMM do, yyyy HH:mm') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Updated At</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelUpdatedAt }}</div>
|
||||
<div class="px-1">
|
||||
{{ $formatDate(_session.updatedAt, 'MMMM do, yyyy HH:mm') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Listened for</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelTimeListened }}</div>
|
||||
<div class="px-1">
|
||||
{{ $elapsedPrettyExtended(_session.timeListening) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Start Time</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelStartTime }}</div>
|
||||
<div class="px-1">
|
||||
{{ $secondsToTimestamp(_session.startTime) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Last Time</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelLastTime }}</div>
|
||||
<div class="px-1">
|
||||
{{ $secondsToTimestamp(_session.currentTime) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">Item</p>
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">{{ $strings.LabelItem }}</p>
|
||||
<div v-if="_session.libraryId" class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Library Id</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelLibrary }} Id</div>
|
||||
<div class="px-1">
|
||||
{{ _session.libraryId }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Library Item Id</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelLibraryItem }} Id</div>
|
||||
<div class="px-1">
|
||||
{{ _session.libraryItemId }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="_session.episodeId" class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Episode Id</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelEpisode }} Id</div>
|
||||
<div class="px-1">
|
||||
{{ _session.episodeId }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Media Type</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelMediaType }}</div>
|
||||
<div class="px-1">
|
||||
{{ _session.mediaType }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center -mx-1 mb-1">
|
||||
<div class="w-40 px-1 text-gray-200">Duration</div>
|
||||
<div class="w-40 px-1 text-gray-200">{{ $strings.LabelDuration }}</div>
|
||||
<div class="px-1">
|
||||
{{ $elapsedPretty(_session.duration) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-1/3">
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mb-2 mt-6 md:mt-0">User</p>
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mb-2 mt-6 md:mt-0">{{ $strings.LabelUser }}</p>
|
||||
<p class="mb-1">{{ _session.userId }}</p>
|
||||
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">Media Player</p>
|
||||
<p class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">{{ $strings.LabelMediaPlayer }}</p>
|
||||
<p class="mb-1">{{ playMethodName }}</p>
|
||||
<p class="mb-1">{{ _session.mediaPlayer }}</p>
|
||||
|
||||
<p v-if="hasDeviceInfo" class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">Device</p>
|
||||
<p v-if="hasDeviceInfo" class="font-semibold uppercase text-xs text-gray-400 tracking-wide mt-6 mb-2">{{ $strings.LabelDevice }}</p>
|
||||
<p v-if="deviceInfo.ipAddress" class="mb-1">{{ deviceInfo.ipAddress }}</p>
|
||||
<p v-if="osDisplayName" class="mb-1">{{ osDisplayName }}</p>
|
||||
<p v-if="deviceInfo.browserName" class="mb-1">{{ deviceInfo.browserName }}</p>
|
||||
<p v-if="clientDisplayName" class="mb-1">{{ clientDisplayName }}</p>
|
||||
<p v-if="deviceInfo.sdkVersion" class="mb-1">SDK Version: {{ deviceInfo.sdkVersion }}</p>
|
||||
<p v-if="deviceInfo.deviceType" class="mb-1">Type: {{ deviceInfo.deviceType }}</p>
|
||||
<p v-if="deviceInfo.sdkVersion" class="mb-1">SDK {{ $strings.LabelVersion }}: {{ deviceInfo.sdkVersion }}</p>
|
||||
<p v-if="deviceInfo.deviceType" class="mb-1">{{ $strings.LabelType }}: {{ deviceInfo.deviceType }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<ui-btn small color="error" @click.stop="deleteSessionClick">Delete</ui-btn>
|
||||
<ui-btn small color="error" @click.stop="deleteSessionClick">{{ $strings.ButtonDelete }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
@ -156,7 +156,7 @@ export default {
|
|||
methods: {
|
||||
deleteSessionClick() {
|
||||
const payload = {
|
||||
message: `Are you sure you want to delete this session?`,
|
||||
message: this.$strings.MessageConfirmDeleteSession,
|
||||
callback: (confirmed) => {
|
||||
if (confirmed) {
|
||||
this.deleteSession()
|
||||
|
@ -172,7 +172,7 @@ export default {
|
|||
.$delete(`/api/sessions/${this._session.id}`)
|
||||
.then(() => {
|
||||
this.processing = false
|
||||
this.$toast.success('Session deleted successfully')
|
||||
this.$toast.success(this.$strings.ToastSessionDeleteSuccess)
|
||||
this.$emit('removedSession')
|
||||
this.show = false
|
||||
})
|
||||
|
@ -180,7 +180,7 @@ export default {
|
|||
this.processing = false
|
||||
console.error('Failed to delete session', error)
|
||||
var errMsg = error.response ? error.response.data || '' : ''
|
||||
this.$toast.error(errMsg || 'Failed to delete session')
|
||||
this.$toast.error(errMsg || this.$strings.ToastSessionDeleteFailed)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<modals-modal v-model="show" name="sleep-timer" :width="350" :height="'unset'">
|
||||
<template #outer>
|
||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden pointer-events-none">
|
||||
<p class="font-book text-3xl text-white truncate pointer-events-none">Sleep Timer</p>
|
||||
<p class="font-book text-3xl text-white truncate pointer-events-none">{{ $strings.HeaderSleepTimer }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
|||
<span class="pl-1 text-base font-mono">30m</span>
|
||||
</ui-btn>
|
||||
</div>
|
||||
<ui-btn class="w-full" @click="$emit('cancel')">Cancel</ui-btn>
|
||||
<ui-btn class="w-full" @click="$emit('cancel')">{{ $strings.ButtonCancel }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
<div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
|
||||
<div v-if="show" class="w-full h-full">
|
||||
<div class="py-4 px-4">
|
||||
<h1 v-if="!showBatchUserCollectionModal" class="text-2xl">Add to Collection</h1>
|
||||
<h1 v-else class="text-2xl">Add {{ selectedBookIds.length }} Books to Collection</h1>
|
||||
<h1 v-if="!showBatchUserCollectionModal" class="text-2xl">{{ $strings.LabelAddToCollection }}</h1>
|
||||
<h1 v-else class="text-2xl">{{ $getString('LabelAddToCollectionBatch', [selectedBookIds.length]) }}</h1>
|
||||
</div>
|
||||
<div class="w-full overflow-y-auto overflow-x-hidden max-h-96">
|
||||
<transition-group name="list-complete" tag="div">
|
||||
|
@ -20,15 +20,15 @@
|
|||
</transition-group>
|
||||
</div>
|
||||
<div v-if="!collections.length" class="flex h-32 items-center justify-center">
|
||||
<p class="text-xl">No Collections</p>
|
||||
<p class="text-xl">{{ $strings.MessageNoCollections }}</p>
|
||||
</div>
|
||||
<div class="w-full h-px bg-white bg-opacity-10" />
|
||||
<form @submit.prevent="submitCreateCollection">
|
||||
<div class="flex px-4 py-2 items-center text-center border-b border-white border-opacity-10 text-white text-opacity-80">
|
||||
<div class="flex-grow px-2">
|
||||
<ui-text-input v-model="newCollectionName" placeholder="New Collection" class="w-full" />
|
||||
<ui-text-input v-model="newCollectionName" :placeholder="$strings.PlaceholderNewCollection" class="w-full" />
|
||||
</div>
|
||||
<ui-btn type="submit" color="success" :padding-x="4" class="h-10">Create</ui-btn>
|
||||
<ui-btn type="submit" color="success" :padding-x="4" class="h-10">{{ $strings.ButtonCreate }}</ui-btn>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -65,7 +65,7 @@ export default {
|
|||
},
|
||||
title() {
|
||||
if (this.showBatchUserCollectionModal) {
|
||||
return `${this.selectedBookIds.length} Items Selected`
|
||||
return this.$getString('MessageItemsSelected', [this.selectedBookIds.length])
|
||||
}
|
||||
return this.selectedLibraryItem ? this.selectedLibraryItem.media.metadata.title : ''
|
||||
},
|
||||
|
@ -124,12 +124,12 @@ export default {
|
|||
.$post(`/api/collections/${collection.id}/batch/remove`, { books: this.selectedBookIds })
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Books removed from collection`, updatedCollection)
|
||||
this.$toast.success('Books removed from collection')
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsRemoveSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to remove books from collection', error)
|
||||
this.$toast.error('Failed to remove books from collection')
|
||||
this.$toast.error(this.$strings.ToastCollectionItemsRemoveFailed)
|
||||
this.processing = false
|
||||
})
|
||||
} else {
|
||||
|
@ -138,12 +138,12 @@ export default {
|
|||
.$delete(`/api/collections/${collection.id}/book/${this.selectedLibraryItemId}`)
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Book removed from collection`, updatedCollection)
|
||||
this.$toast.success('Book removed from collection')
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsRemoveSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to remove book from collection', error)
|
||||
this.$toast.error('Failed to remove book from collection')
|
||||
this.$toast.error(this.$strings.ToastCollectionItemsRemoveFailed)
|
||||
this.processing = false
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,23 +19,23 @@
|
|||
<div class="flex-grow">
|
||||
<div class="flex">
|
||||
<div class="w-3/4 p-2">
|
||||
<ui-text-input-with-label v-model="authorCopy.name" :disabled="processing" label="Name" />
|
||||
<ui-text-input-with-label v-model="authorCopy.name" :disabled="processing" :label="$strings.LabelName" />
|
||||
</div>
|
||||
<div class="flex-grow p-2">
|
||||
<ui-text-input-with-label v-model="authorCopy.asin" :disabled="processing" label="ASIN" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<ui-text-input-with-label v-model="authorCopy.imagePath" :disabled="processing" label="Photo Path/URL" />
|
||||
<ui-text-input-with-label v-model="authorCopy.imagePath" :disabled="processing" :label="$strings.LabelPhotoPathURL" />
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<ui-textarea-with-label v-model="authorCopy.description" :disabled="processing" label="Description" :rows="8" />
|
||||
<ui-textarea-with-label v-model="authorCopy.description" :disabled="processing" :label="$strings.LabelDescription" :rows="8" />
|
||||
</div>
|
||||
|
||||
<div class="flex pt-2 px-2">
|
||||
<ui-btn type="button" @click="searchAuthor">Quick Match</ui-btn>
|
||||
<ui-btn type="button" @click="searchAuthor">{{ $strings.ButtonQuickMatch }}</ui-btn>
|
||||
<div class="flex-grow" />
|
||||
<ui-btn type="submit">Submit</ui-btn>
|
||||
<ui-btn type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -84,7 +84,7 @@ export default {
|
|||
return this.author.id
|
||||
},
|
||||
title() {
|
||||
return 'Edit Author'
|
||||
return this.$strings.HeaderUpdateAuthor
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -103,23 +103,23 @@ export default {
|
|||
}
|
||||
})
|
||||
if (!Object.keys(updatePayload).length) {
|
||||
this.$toast.info('No updates are necessary')
|
||||
this.$toast.info(this.$strings.MessageNoUpdateNecessary)
|
||||
return
|
||||
}
|
||||
this.processing = true
|
||||
var result = await this.$axios.$patch(`/api/authors/${this.authorId}`, updatePayload).catch((error) => {
|
||||
console.error('Failed', error)
|
||||
this.$toast.error('Failed to update author')
|
||||
this.$toast.error(this.$strings.ToastAuthorUpdateFailed)
|
||||
return null
|
||||
})
|
||||
if (result) {
|
||||
if (result.updated) {
|
||||
this.$toast.success('Author updated')
|
||||
this.$toast.success(this.$strings.ToastAuthorUpdateSuccess)
|
||||
this.show = false
|
||||
} else if (result.merged) {
|
||||
this.$toast.success('Author merged')
|
||||
this.$toast.success(this.$strings.ToastAuthorUpdateMerged)
|
||||
this.show = false
|
||||
} else this.$toast.info('No updates were needed')
|
||||
} else this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
||||
}
|
||||
this.processing = false
|
||||
},
|
||||
|
@ -131,11 +131,11 @@ export default {
|
|||
this.processing = true
|
||||
var result = await this.$axios.$patch(`/api/authors/${this.authorId}`, updatePayload).catch((error) => {
|
||||
console.error('Failed', error)
|
||||
this.$toast.error('Failed to remove image')
|
||||
this.$toast.error(this.$strings.ToastAuthorImageRemoveFailed)
|
||||
return null
|
||||
})
|
||||
if (result && result.updated) {
|
||||
this.$toast.success('Author image removed')
|
||||
this.$toast.success(this.$strings.ToastAuthorImageRemoveSuccess)
|
||||
}
|
||||
this.processing = false
|
||||
},
|
||||
|
@ -157,8 +157,8 @@ export default {
|
|||
if (!response) {
|
||||
this.$toast.error('Author not found')
|
||||
} else if (response.updated) {
|
||||
if (response.author.imagePath) this.$toast.success('Author was updated')
|
||||
else this.$toast.success('Author was updated (no image found)')
|
||||
if (response.author.imagePath) this.$toast.success(this.$strings.ToastAuthorUpdateSuccess)
|
||||
else this.$toast.success(this.$strings.ToastAuthorUpdateSuccessNoImageFound)
|
||||
} else {
|
||||
this.$toast.info('No updates were made for Author')
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ export default {
|
|||
this.$toast.success('Item details updated')
|
||||
return true
|
||||
} else {
|
||||
this.$toast.info('No updates were necessary')
|
||||
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -2,29 +2,29 @@
|
|||
<div class="w-full h-full overflow-y-auto overflow-x-hidden px-4 py-6">
|
||||
<div class="w-full mb-4">
|
||||
<div v-if="userIsAdminOrUp" class="flex items-end justify-end mb-4">
|
||||
<ui-text-input-with-label ref="lastCheckInput" v-model="lastEpisodeCheckInput" :disabled="checkingNewEpisodes" type="datetime-local" label="Look for new episodes after this date" class="max-w-xs mr-2" />
|
||||
<ui-text-input-with-label ref="maxEpisodesInput" v-model="maxEpisodesToDownload" :disabled="checkingNewEpisodes" type="number" label="Max episodes" class="w-16 mr-2" input-class="h-10">
|
||||
<ui-text-input-with-label ref="lastCheckInput" v-model="lastEpisodeCheckInput" :disabled="checkingNewEpisodes" type="datetime-local" :label="$strings.LabelLookForNewEpisodesAfterDate" class="max-w-xs mr-2" />
|
||||
<ui-text-input-with-label ref="maxEpisodesInput" v-model="maxEpisodesToDownload" :disabled="checkingNewEpisodes" type="number" :label="$strings.LabelLimit" class="w-16 mr-2" input-class="h-10">
|
||||
<div class="flex -mb-0.5">
|
||||
<p class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': checkingNewEpisodes }">Limit</p>
|
||||
<p class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': checkingNewEpisodes }">{{ $strings.LabelLimit }}</p>
|
||||
<ui-tooltip direction="top" text="Max # of episodes to download. Use 0 for unlimited.">
|
||||
<span class="material-icons text-base">info_outlined</span>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
</ui-text-input-with-label>
|
||||
<ui-btn :loading="checkingNewEpisodes" @click="checkForNewEpisodes">Check & Download New Episodes</ui-btn>
|
||||
<ui-btn :loading="checkingNewEpisodes" @click="checkForNewEpisodes">{{ $strings.ButtonCheckAndDownloadNewEpisodes }}</ui-btn>
|
||||
</div>
|
||||
|
||||
<div v-if="episodes.length" class="w-full p-4 bg-primary">
|
||||
<p>Podcast Episodes</p>
|
||||
<p>{{ $strings.HeaderEpisodes }}</p>
|
||||
</div>
|
||||
<div v-if="!episodes.length" class="flex my-4 text-center justify-center text-xl">No Episodes</div>
|
||||
<div v-if="!episodes.length" class="flex my-4 text-center justify-center text-xl">{{ $strings.MessageNoEpisodes }}</div>
|
||||
<table v-else class="text-sm tracksTable">
|
||||
<tr class="font-book">
|
||||
<th class="text-left">Sort #</th>
|
||||
<th class="text-left whitespace-nowrap">Episode #</th>
|
||||
<th class="text-left">Title</th>
|
||||
<th class="text-center w-28">Duration</th>
|
||||
<th class="text-center w-28">Size</th>
|
||||
<th class="text-left whitespace-nowrap">{{ $strings.LabelEpisode }}</th>
|
||||
<th class="text-left">{{ $strings.EpisodeTitle }}</th>
|
||||
<th class="text-center w-28">{{ $strings.EpisodeDuration }}</th>
|
||||
<th class="text-center w-28">{{ $strings.EpisodeSize }}</th>
|
||||
</tr>
|
||||
<tr v-for="episode in episodes" :key="episode.id">
|
||||
<td class="text-left">
|
||||
|
|
|
@ -474,9 +474,9 @@ export default {
|
|||
return false
|
||||
})
|
||||
if (success) {
|
||||
this.$toast.success('Item Cover Updated')
|
||||
this.$toast.success(this.$strings.ToastItemCoverUpdateSuccess)
|
||||
} else {
|
||||
this.$toast.error('Item Cover Failed to Update')
|
||||
this.$toast.error(this.$strings.ToastItemCoverUpdateFailed)
|
||||
}
|
||||
console.log('Updated cover')
|
||||
delete updatePayload.metadata.cover
|
||||
|
@ -490,14 +490,14 @@ export default {
|
|||
})
|
||||
if (updateResult) {
|
||||
if (updateResult.updated) {
|
||||
this.$toast.success('Item details updated')
|
||||
this.$toast.success(this.$strings.ToastItemDetailsUpdateSuccess)
|
||||
} else {
|
||||
this.$toast.info('No detail updates were necessary')
|
||||
this.$toast.info(this.$strings.ToastItemDetailsUpdateUnneeded)
|
||||
}
|
||||
this.clearSelectedMatch()
|
||||
this.$emit('selectTab', 'details')
|
||||
} else {
|
||||
this.$toast.error('Item Details Failed to Update')
|
||||
this.$toast.error(this.$strings.ToastItemDetailsUpdateFailed)
|
||||
}
|
||||
} else {
|
||||
this.clearSelectedMatch()
|
||||
|
|
|
@ -153,7 +153,7 @@ export default {
|
|||
this.$toast.success('Item details updated')
|
||||
return true
|
||||
} else {
|
||||
this.$toast.info('No updates were necessary')
|
||||
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="!mediaTracks.length" class="text-lg text-center my-8">No audio tracks</p>
|
||||
<p v-if="!mediaTracks.length" class="text-lg text-center my-8">{{ $strings.MessageNoAudioTracks }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -53,20 +53,22 @@ export default {
|
|||
folders: [],
|
||||
showDirectoryPicker: false,
|
||||
newFolderPath: '',
|
||||
mediaType: null,
|
||||
mediaTypes: [
|
||||
{
|
||||
value: 'book',
|
||||
text: 'Books'
|
||||
},
|
||||
{
|
||||
value: 'podcast',
|
||||
text: 'Podcasts'
|
||||
}
|
||||
]
|
||||
mediaType: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mediaTypes() {
|
||||
return [
|
||||
{
|
||||
value: 'book',
|
||||
text: this.$strings.LabelBooks
|
||||
},
|
||||
{
|
||||
value: 'podcast',
|
||||
text: this.$strings.LabelPodcasts
|
||||
}
|
||||
]
|
||||
},
|
||||
folderPaths() {
|
||||
return this.folders.map((f) => f.fullPath)
|
||||
},
|
||||
|
|
|
@ -192,14 +192,14 @@ export default {
|
|||
.then((res) => {
|
||||
this.processing = false
|
||||
this.show = false
|
||||
this.$toast.success(`Library "${res.name}" updated successfully`)
|
||||
this.$toast.success(this.$getString('ToastLibraryUpdateSuccess', [res.name]))
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
if (error.response && error.response.data) {
|
||||
this.$toast.error(error.response.data)
|
||||
} else {
|
||||
this.$toast.error('Failed to update library')
|
||||
this.$toast.error(this.$strings.ToastLibraryUpdateFailed)
|
||||
}
|
||||
this.processing = false
|
||||
})
|
||||
|
@ -211,7 +211,7 @@ export default {
|
|||
.then((res) => {
|
||||
this.processing = false
|
||||
this.show = false
|
||||
this.$toast.success(`Library "${res.name}" created successfully`)
|
||||
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
||||
if (!this.$store.state.libraries.currentLibraryId) {
|
||||
console.log('Setting initially library id', res.id)
|
||||
// First library added
|
||||
|
@ -223,7 +223,7 @@ export default {
|
|||
if (error.response && error.response.data) {
|
||||
this.$toast.error(error.response.data)
|
||||
} else {
|
||||
this.$toast.error('Failed to create library')
|
||||
this.$toast.error(this.$strings.ToastLibraryCreateFailed)
|
||||
}
|
||||
this.processing = false
|
||||
})
|
||||
|
|
|
@ -26,12 +26,12 @@ export default {
|
|||
tabs: [
|
||||
{
|
||||
id: 'details',
|
||||
title: 'Details',
|
||||
title: this.$strings.HeaderDetails,
|
||||
component: 'modals-podcast-tabs-episode-details'
|
||||
},
|
||||
{
|
||||
id: 'match',
|
||||
title: 'Match',
|
||||
title: this.$strings.HeaderMatch,
|
||||
component: 'modals-podcast-tabs-episode-match'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -7,45 +7,45 @@
|
|||
</template>
|
||||
<div ref="wrapper" id="podcast-wrapper" class="p-2 md:p-8 w-full text-sm py-2 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-x-hidden overflow-y-auto" style="max-height: 80vh">
|
||||
<div class="w-full">
|
||||
<p class="text-lg font-semibold mb-2 px-2">Details</p>
|
||||
<p class="text-lg font-semibold mb-2 px-2">{{ $strings.HeaderDetails }}</p>
|
||||
|
||||
<div v-if="podcast.imageUrl" class="p-2 w-full">
|
||||
<img :src="podcast.imageUrl" class="h-16 w-16 object-contain" />
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.title" label="Title" @input="titleUpdated" />
|
||||
<ui-text-input-with-label v-model="podcast.title" :label="$strings.LabelTitle" @input="titleUpdated" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.author" label="Author" />
|
||||
<ui-text-input-with-label v-model="podcast.author" :label="$strings.LabelAuthor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.feedUrl" label="Feed URL" readonly />
|
||||
<ui-text-input-with-label v-model="podcast.feedUrl" :label="$strings.LabelFeedURL" readonly />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" label="Genres" />
|
||||
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" :label="$strings.LabelGenres" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 w-full">
|
||||
<ui-textarea-with-label v-model="podcast.description" label="Description" :rows="3" />
|
||||
<ui-textarea-with-label v-model="podcast.description" :label="$strings.LabelDescription" :rows="3" />
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" label="Folder" @input="folderUpdated" />
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" :label="$strings.LabelFolder" @input="folderUpdated" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/2 p-2">
|
||||
<ui-text-input-with-label v-model="fullPath" label="Podcast Path" input-class="h-10" readonly />
|
||||
<ui-text-input-with-label v-model="fullPath" :label="`${$strings.LabelPodcast} ${$strings.LabelPath}`" input-class="h-10" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center py-4 px-2">
|
||||
<div class="flex-grow" />
|
||||
<div class="px-4">
|
||||
<ui-checkbox v-model="podcast.autoDownloadEpisodes" label="Auto Download Episodes" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-sm md:text-base font-semibold" />
|
||||
<ui-checkbox v-model="podcast.autoDownloadEpisodes" :label="$strings.LabelAutoDownloadEpisodes" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-sm md:text-base font-semibold" />
|
||||
</div>
|
||||
<ui-btn color="success" @click="submit">Add Podcast</ui-btn>
|
||||
<ui-btn color="success" @click="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
@ -182,12 +182,12 @@ export default {
|
|||
.$post('/api/podcasts', podcastPayload)
|
||||
.then((libraryItem) => {
|
||||
this.processing = false
|
||||
this.$toast.success('Podcast created successfully')
|
||||
this.$toast.success(this.$strings.ToastPodcastCreateSuccess)
|
||||
this.show = false
|
||||
this.$router.push(`/item/${libraryItem.id}`)
|
||||
})
|
||||
.catch((error) => {
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to create podcast'
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : this.$strings.ToastPodcastCreateFailed
|
||||
console.error('Failed to create podcast', error)
|
||||
this.processing = false
|
||||
this.$toast.error(errorMsg)
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
<div class="w-full p-4">
|
||||
<div class="flex items-center -mx-2 mb-2">
|
||||
<div class="w-full md:w-2/3 p-2">
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" label="Folder" />
|
||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" :label="$strings.LabelFolder" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/3 p-2 pt-6">
|
||||
<ui-checkbox v-model="autoDownloadEpisodes" label="Auto Download New Episodes" checkbox-bg="primary" border-color="gray-600" label-class="text-sm font-semibold pl-2" />
|
||||
<ui-checkbox v-model="autoDownloadEpisodes" :label="$strings.LabelAutoDownloadEpisodes" checkbox-bg="primary" border-color="gray-600" label-class="text-sm font-semibold pl-2" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-lg font-semibold mb-2">Podcasts to Add</p>
|
||||
<p class="text-lg font-semibold mb-2">{{ $strings.HeaderPodcastsToAdd }}</p>
|
||||
|
||||
<div class="w-full overflow-y-auto" style="max-height: 50vh">
|
||||
<template v-for="(feed, index) in feedMetadata">
|
||||
|
@ -26,7 +26,7 @@
|
|||
</div>
|
||||
<div class="flex items-center py-4">
|
||||
<div class="flex-grow" />
|
||||
<ui-btn color="success" @click="submit">Add Podcasts</ui-btn>
|
||||
<ui-btn color="success" @click="submit">{{ $strings.ButtonAddPodcasts }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
@ -141,10 +141,10 @@ export default {
|
|||
await this.$axios
|
||||
.$post('/api/podcasts', podcastPayload)
|
||||
.then(() => {
|
||||
this.$toast.success(`${podcastPayload.media.metadata.title}: Podcast created successfully`)
|
||||
this.$toast.success(`${podcastPayload.media.metadata.title}: ${this.$strings.ToastPodcastCreateSuccess}`)
|
||||
})
|
||||
.catch((error) => {
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to create podcast'
|
||||
var errorMsg = error.response && error.response.data ? error.response.data : this.$strings.ToastPodcastCreateFailed
|
||||
console.error('Failed to create podcast', podcastPayload, error)
|
||||
this.$toast.error(`${podcastPayload.media.metadata.title}: ${errorMsg}`)
|
||||
})
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
<div ref="wrapper" class="px-8 py-6 w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden">
|
||||
<div class="mb-4">
|
||||
<p v-if="episode" class="text-lg text-gray-200 mb-4">
|
||||
Are you sure you want to remove episode<br /><span class="text-base">{{ episodeTitle }}</span
|
||||
>?
|
||||
{{ $getString('MessageConfirmRemoveEpisode', [episodeTitle]) }}
|
||||
</p>
|
||||
<p v-else class="text-lg text-gray-200 mb-4">Are you sure you want to remove {{ episodes.length }} episodes?</p>
|
||||
<p v-else class="text-lg text-gray-200 mb-4">{{ $getString('MessageConfirmRemoveEpisodes', [episodes.length]) }}</p>
|
||||
<p class="text-xs font-semibold text-warning text-opacity-90">Note: This does not delete the audio file unless toggling "Hard delete file"</p>
|
||||
</div>
|
||||
<div class="flex justify-between items-center pt-4">
|
||||
<ui-checkbox v-model="hardDeleteFile" label="Hard delete file" check-color="error" checkbox-bg="bg" small label-class="text-base text-gray-200 pl-3" />
|
||||
<ui-checkbox v-model="hardDeleteFile" :label="$strings.LabelHardDeleteFile" check-color="error" checkbox-bg="bg" small label-class="text-base text-gray-200 pl-3" />
|
||||
|
||||
<ui-btn @click="submit">{{ btnText }}</ui-btn>
|
||||
</div>
|
||||
|
@ -61,12 +60,11 @@ export default {
|
|||
return null
|
||||
},
|
||||
title() {
|
||||
if (this.episodes.length > 1) return `Remove ${this.episodes.length} episodes`
|
||||
return 'Remove Episode'
|
||||
if (this.episodes.length > 1) return this.$getString('HeaderRemoveEpisodes', [this.episodes.length])
|
||||
return this.$strings.HeaderRemoveEpisode
|
||||
},
|
||||
btnText() {
|
||||
if (this.episodes.length > 1) return this.hardDeleteFile ? `Delete ${this.episodes.length} episodes` : `Remove ${this.episodes.length} episodes`
|
||||
return this.hardDeleteFile ? 'Delete episode' : 'Remove episode'
|
||||
return this.hardDeleteFile ? this.$strings.ButtonDelete : this.$strings.ButtonRemove
|
||||
},
|
||||
episodeTitle() {
|
||||
return this.episode ? this.episode.title : null
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<modals-modal v-model="show" name="podcast-episode-view-modal" :width="800" :height="'unset'" :processing="processing">
|
||||
<template #outer>
|
||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||
<p class="font-book text-3xl text-white truncate">Episode</p>
|
||||
<p class="font-book text-3xl text-white truncate">{{ $strings.LabelEpisode }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<div ref="wrapper" class="p-4 w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-y-auto" style="max-height: 80vh">
|
||||
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
<p class="text-lg font-semibold mb-6">{{ title }}</p>
|
||||
<div v-if="description" class="default-style" v-html="description" />
|
||||
<p v-else class="mb-2">No description</p>
|
||||
<p v-else class="mb-2">{{ $strings.MessageNoDescription }}</p>
|
||||
</div>
|
||||
</modals-modal>
|
||||
</template>
|
||||
|
|
|
@ -2,29 +2,29 @@
|
|||
<div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-1/5 p-1">
|
||||
<ui-text-input-with-label v-model="newEpisode.season" label="Season" />
|
||||
<ui-text-input-with-label v-model="newEpisode.season" :label="$strings.LabelSeason" />
|
||||
</div>
|
||||
<div class="w-1/5 p-1">
|
||||
<ui-text-input-with-label v-model="newEpisode.episode" label="Episode" />
|
||||
<ui-text-input-with-label v-model="newEpisode.episode" :label="$strings.LabelEpisode" />
|
||||
</div>
|
||||
<div class="w-1/5 p-1">
|
||||
<ui-text-input-with-label v-model="newEpisode.episodeType" label="Episode Type" />
|
||||
<ui-text-input-with-label v-model="newEpisode.episodeType" :label="$strings.LabelEpisodeType" />
|
||||
</div>
|
||||
<div class="w-2/5 p-1">
|
||||
<ui-text-input-with-label v-model="pubDateInput" @input="updatePubDate" type="datetime-local" label="Pub Date" />
|
||||
<ui-text-input-with-label v-model="pubDateInput" @input="updatePubDate" type="datetime-local" :label="$strings.LabelPubDate" />
|
||||
</div>
|
||||
<div class="w-full p-1">
|
||||
<ui-text-input-with-label v-model="newEpisode.title" label="Title" />
|
||||
<ui-text-input-with-label v-model="newEpisode.title" :label="$strings.LabelTitle" />
|
||||
</div>
|
||||
<div class="w-full p-1">
|
||||
<ui-textarea-with-label v-model="newEpisode.subtitle" label="Subtitle" :rows="3" />
|
||||
<ui-textarea-with-label v-model="newEpisode.subtitle" :label="$strings.LabelSubtitle" :rows="3" />
|
||||
</div>
|
||||
<div class="w-full p-1 default-style">
|
||||
<ui-rich-text-editor label="Description" v-model="newEpisode.description" />
|
||||
<ui-rich-text-editor :label="$strings.LabelDescription" v-model="newEpisode.description" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end pt-4">
|
||||
<ui-btn @click="submit">Submit</ui-btn>
|
||||
<ui-btn @click="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||
</div>
|
||||
<div v-if="enclosureUrl" class="py-4">
|
||||
<p class="text-xs text-gray-300 font-semibold">Episode URL from RSS feed</p>
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
<div style="min-height: 200px">
|
||||
<template v-if="!podcastFeedUrl">
|
||||
<div class="py-8">
|
||||
<widgets-alert type="error">Podcast has no RSS feed url to use for matching</widgets-alert>
|
||||
<widgets-alert type="error">{{ $strings.MessagePodcastHasNoRSSFeedForMatching }}</widgets-alert>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<form @submit.prevent="submitForm">
|
||||
<div class="flex mb-2">
|
||||
<ui-text-input-with-label v-model="episodeTitle" :disabled="isProcessing" label="Episode Title" class="pr-1" />
|
||||
<ui-btn class="mt-5 ml-1" :loading="isProcessing" type="submit">Search</ui-btn>
|
||||
<ui-text-input-with-label v-model="episodeTitle" :disabled="isProcessing" :label="$strings.LabelEpisodeTitle" class="pr-1" />
|
||||
<ui-btn class="mt-5 ml-1" :loading="isProcessing" type="submit">{{ $strings.ButtonSearch }}</ui-btn>
|
||||
</div>
|
||||
</form>
|
||||
<div v-if="!isProcessing && searchedTitle && !episodesFound.length" class="w-full py-8">
|
||||
<p class="text-center text-lg">No episode matches found</p>
|
||||
<p class="text-center text-lg">{{ $strings.MessageNoEpisodeMatchesFound }}</p>
|
||||
</div>
|
||||
<div v-for="(episode, index) in episodesFound" :key="index" class="w-full py-4 border-b border-white border-opacity-5 hover:bg-gray-300 hover:bg-opacity-10 cursor-pointer px-2" @click.stop="selectEpisode(episode)">
|
||||
<p v-if="episode.episode" class="font-semibold text-gray-200">#{{ episode.episode }}</p>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</template>
|
||||
<div ref="wrapper" class="px-8 py-6 w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden">
|
||||
<div v-if="currentFeedUrl" class="w-full">
|
||||
<p class="text-lg font-semibold mb-4">Podcast RSS Feed is Open</p>
|
||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
|
||||
|
||||
<div class="w-full relative">
|
||||
<ui-text-input v-model="currentFeedUrl" readonly />
|
||||
|
@ -16,20 +16,20 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-else class="w-full">
|
||||
<p class="text-lg font-semibold mb-4">Open RSS Feed</p>
|
||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderOpenRSSFeed }}</p>
|
||||
|
||||
<div class="w-full relative mb-2">
|
||||
<ui-text-input-with-label v-model="newFeedSlug" label="RSS Feed Slug" />
|
||||
<p class="text-xs text-gray-400 py-0.5 px-1">Feed will be {{ demoFeedUrl }}</p>
|
||||
<ui-text-input-with-label v-model="newFeedSlug" :label="$strings.LabelRSSFeedSlug" />
|
||||
<p class="text-xs text-gray-400 py-0.5 px-1">{{ $getString('MessageFeedURLWillBe', [demoFeedUrl]) }}</p>
|
||||
</div>
|
||||
|
||||
<p v-if="isHttp" class="w-full pt-2 text-warning text-xs">Warning: Most podcast apps will require the RSS feed URL is using HTTPS</p>
|
||||
<p v-if="hasEpisodesWithoutPubDate" class="w-full pt-2 text-warning text-xs">Warning: 1 or more of your episodes do not have a Pub Date. Some podcast apps require this.</p>
|
||||
<p v-if="isHttp" class="w-full pt-2 text-warning text-xs">{{ $strings.NoteRSSFeedPodcastAppsHttps }}</p>
|
||||
<p v-if="hasEpisodesWithoutPubDate" class="w-full pt-2 text-warning text-xs">{{ $strings.NoteRSSFeedPodcastAppsPubDate }}</p>
|
||||
</div>
|
||||
<div v-show="userIsAdminOrUp" class="flex items-center pt-6">
|
||||
<div class="flex-grow" />
|
||||
<ui-btn v-if="currentFeedUrl" color="error" small @click="closeFeed">Close RSS Feed</ui-btn>
|
||||
<ui-btn v-else color="success" small @click="openFeed">Open RSS Feed</ui-btn>
|
||||
<ui-btn v-if="currentFeedUrl" color="error" small @click="closeFeed">{{ $strings.ButtonCloseFeed }}</ui-btn>
|
||||
<ui-btn v-else color="success" small @click="openFeed">{{ $strings.ButtonOpenFeed }}</ui-btn>
|
||||
</div>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
@ -144,14 +144,14 @@ export default {
|
|||
this.$axios
|
||||
.$post(`/api/items/${this.libraryItem.id}/close-feed`)
|
||||
.then(() => {
|
||||
this.$toast.success('RSS Feed Closed')
|
||||
this.$toast.success(this.$strings.ToastRSSFeedCloseSuccess)
|
||||
this.show = false
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to close RSS feed', error)
|
||||
this.processing = false
|
||||
this.$toast.error()
|
||||
this.$toast.error(this.$strings.ToastRSSFeedCloseFailed)
|
||||
})
|
||||
},
|
||||
init() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue