mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-06-05 02:02:44 +02:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24923c0009 | |||
| a9036c9738 | |||
| f9f7fbed33 | |||
| 53b5bee736 | |||
| d0b3726905 | |||
| 7a6864507e | |||
| e20563f2e1 | |||
| fea5f8f3d4 | |||
| f9bb529b85 | |||
| 60e348fcc1 | |||
| f194c5be0e | |||
| 47712e63f1 | |||
| 790c1fb34a | |||
| 9cca731acc | |||
| 48f232790a | |||
| 3c55aa5f43 | |||
| 8c1edb30a6 | |||
| 5e64af4448 | |||
| 9f60017cfe | |||
| b6a86d11d2 | |||
| db86bfd63d | |||
| 7ff72a8920 | |||
| 2c4f86d148 |
@@ -108,9 +108,9 @@ export default {
|
|||||||
if (res.warning) {
|
if (res.warning) {
|
||||||
this.$toast.warning(res.warning)
|
this.$toast.warning(res.warning)
|
||||||
} else if (res.updated) {
|
} else if (res.updated) {
|
||||||
this.$toast.success(this.$strings.ToastNoUpdatesNecessary)
|
this.$toast.success(this.$strings.ToastItemDetailsUpdateSuccess)
|
||||||
} else {
|
} else {
|
||||||
this.$toast.info(this.$strings.ToastItemDetailsUpdateUnneeded)
|
this.$toast.info(this.$strings.ToastNoUpdatesNecessary)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -170,7 +170,7 @@ export default {
|
|||||||
this.isProcessing = false
|
this.isProcessing = false
|
||||||
if (updateResult) {
|
if (updateResult) {
|
||||||
if (updateResult.updated) {
|
if (updateResult.updated) {
|
||||||
this.$toast.success(this.$strings.MessageItemDetailsUpdated)
|
this.$toast.success(this.$strings.ToastItemDetailsUpdateSuccess)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
||||||
|
|||||||
@@ -3,67 +3,67 @@
|
|||||||
<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="$strings.LabelTitle" />
|
<ui-text-input-with-label ref="titleInput" v-model="details.title" :label="$strings.LabelTitle" @input="handleInputChange" />
|
||||||
</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="$strings.LabelSubtitle" />
|
<ui-text-input-with-label ref="subtitleInput" v-model="details.subtitle" :label="$strings.LabelSubtitle" @input="handleInputChange" />
|
||||||
</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, uses filter data -->
|
<!-- Authors filter only contains authors in this library, uses filter data -->
|
||||||
<ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" :label="$strings.LabelAuthors" filter-key="authors" />
|
<ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" :label="$strings.LabelAuthors" filter-key="authors" @input="handleInputChange" />
|
||||||
</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="$strings.LabelPublishYear" />
|
<ui-text-input-with-label ref="publishYearInput" v-model="details.publishedYear" type="number" :label="$strings.LabelPublishYear" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex mt-2 -mx-1">
|
<div class="flex mt-2 -mx-1">
|
||||||
<div class="flex-grow px-1">
|
<div class="flex-grow px-1">
|
||||||
<widgets-series-input-widget v-model="details.series" />
|
<widgets-series-input-widget v-model="details.series" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" />
|
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" @input="handleInputChange" />
|
||||||
|
|
||||||
<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="$strings.LabelGenres" :items="genres" />
|
<ui-multi-select ref="genresSelect" v-model="details.genres" :label="$strings.LabelGenres" :items="genres" @input="handleInputChange" />
|
||||||
</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="$strings.LabelTags" :items="tags" />
|
<ui-multi-select ref="tagsSelect" v-model="newTags" :label="$strings.LabelTags" :items="tags" @input="handleInputChange" />
|
||||||
</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="$strings.LabelNarrators" :items="narrators" />
|
<ui-multi-select ref="narratorsSelect" v-model="details.narrators" :label="$strings.LabelNarrators" :items="narrators" @input="handleInputChange" />
|
||||||
</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" @input="handleInputChange" />
|
||||||
</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="asinInput" v-model="details.asin" label="ASIN" />
|
<ui-text-input-with-label ref="asinInput" v-model="details.asin" label="ASIN" @input="handleInputChange" />
|
||||||
</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/4 px-1">
|
<div class="w-full md:w-1/4 px-1">
|
||||||
<ui-text-input-with-label ref="publisherInput" v-model="details.publisher" :label="$strings.LabelPublisher" />
|
<ui-text-input-with-label ref="publisherInput" v-model="details.publisher" :label="$strings.LabelPublisher" @input="handleInputChange" />
|
||||||
</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="$strings.LabelLanguage" />
|
<ui-text-input-with-label ref="languageInput" v-model="details.language" :label="$strings.LabelLanguage" @input="handleInputChange" />
|
||||||
</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="$strings.LabelExplicit" 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" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</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.abridged" :label="$strings.LabelAbridged" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
<ui-checkbox v-model="details.abridged" :label="$strings.LabelAbridged" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,6 +132,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleInputChange() {
|
||||||
|
this.$emit('change', {
|
||||||
|
libraryItemId: this.libraryItem.id,
|
||||||
|
hasChanges: this.checkForChanges().hasChanges
|
||||||
|
})
|
||||||
|
},
|
||||||
getDetails() {
|
getDetails() {
|
||||||
this.forceBlur()
|
this.forceBlur()
|
||||||
return this.checkForChanges()
|
return this.checkForChanges()
|
||||||
@@ -172,6 +178,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.handleInputChange()
|
||||||
},
|
},
|
||||||
forceBlur() {
|
forceBlur() {
|
||||||
if (this.$refs.titleInput) this.$refs.titleInput.blur()
|
if (this.$refs.titleInput) this.$refs.titleInput.blur()
|
||||||
|
|||||||
@@ -3,45 +3,45 @@
|
|||||||
<form class="w-full h-full px-4 py-6" @submit.prevent="submitForm">
|
<form class="w-full h-full px-4 py-6" @submit.prevent="submitForm">
|
||||||
<div class="flex -mx-1">
|
<div class="flex -mx-1">
|
||||||
<div class="w-1/2 px-1">
|
<div class="w-1/2 px-1">
|
||||||
<ui-text-input-with-label ref="titleInput" v-model="details.title" :label="$strings.LabelTitle" />
|
<ui-text-input-with-label ref="titleInput" v-model="details.title" :label="$strings.LabelTitle" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1">
|
<div class="flex-grow px-1">
|
||||||
<ui-text-input-with-label ref="authorInput" v-model="details.author" :label="$strings.LabelAuthor" />
|
<ui-text-input-with-label ref="authorInput" v-model="details.author" :label="$strings.LabelAuthor" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ui-text-input-with-label ref="feedUrlInput" v-model="details.feedUrl" :label="$strings.LabelRSSFeedURL" class="mt-2" />
|
<ui-text-input-with-label ref="feedUrlInput" v-model="details.feedUrl" :label="$strings.LabelRSSFeedURL" class="mt-2" @input="handleInputChange" />
|
||||||
|
|
||||||
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" />
|
<ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" @input="handleInputChange" />
|
||||||
|
|
||||||
<div class="flex mt-2 -mx-1">
|
<div class="flex mt-2 -mx-1">
|
||||||
<div class="w-1/2 px-1">
|
<div class="w-1/2 px-1">
|
||||||
<ui-multi-select ref="genresSelect" v-model="details.genres" :label="$strings.LabelGenres" :items="genres" />
|
<ui-multi-select ref="genresSelect" v-model="details.genres" :label="$strings.LabelGenres" :items="genres" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1">
|
<div class="flex-grow px-1">
|
||||||
<ui-multi-select ref="tagsSelect" v-model="newTags" :label="$strings.LabelTags" :items="tags" />
|
<ui-multi-select ref="tagsSelect" v-model="newTags" :label="$strings.LabelTags" :items="tags" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex mt-2 -mx-1">
|
<div class="flex mt-2 -mx-1">
|
||||||
<div class="w-1/4 px-1">
|
<div class="w-1/4 px-1">
|
||||||
<ui-text-input-with-label ref="releaseDateInput" v-model="details.releaseDate" :label="$strings.LabelReleaseDate" />
|
<ui-text-input-with-label ref="releaseDateInput" v-model="details.releaseDate" :label="$strings.LabelReleaseDate" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/4 px-1">
|
<div class="w-1/4 px-1">
|
||||||
<ui-text-input-with-label ref="itunesIdInput" v-model="details.itunesId" label="iTunes ID" />
|
<ui-text-input-with-label ref="itunesIdInput" v-model="details.itunesId" label="iTunes ID" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/4 px-1">
|
<div class="w-1/4 px-1">
|
||||||
<ui-text-input-with-label ref="languageInput" v-model="details.language" :label="$strings.LabelLanguage" />
|
<ui-text-input-with-label ref="languageInput" v-model="details.language" :label="$strings.LabelLanguage" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow px-1 pt-6">
|
<div class="flex-grow px-1 pt-6">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<ui-checkbox v-model="details.explicit" :label="$strings.LabelExplicit" 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" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mt-2 -mx-1">
|
<div class="flex mt-2 -mx-1">
|
||||||
<div class="w-1/4 px-1">
|
<div class="w-1/4 px-1">
|
||||||
<ui-dropdown :label="$strings.LabelPodcastType" v-model="details.type" :items="podcastTypes" small class="max-w-52" />
|
<ui-dropdown :label="$strings.LabelPodcastType" v-model="details.type" :items="podcastTypes" small class="max-w-52" @input="handleInputChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -105,6 +105,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleInputChange() {
|
||||||
|
this.$emit('change', {
|
||||||
|
libraryItemId: this.libraryItem.id,
|
||||||
|
hasChanges: this.checkForChanges().hasChanges
|
||||||
|
})
|
||||||
|
},
|
||||||
getDetails() {
|
getDetails() {
|
||||||
this.forceBlur()
|
this.forceBlur()
|
||||||
return this.checkForChanges()
|
return this.checkForChanges()
|
||||||
@@ -136,6 +142,8 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.handleInputChange()
|
||||||
},
|
},
|
||||||
forceBlur() {
|
forceBlur() {
|
||||||
if (this.$refs.titleInput) this.$refs.titleInput.blur()
|
if (this.$refs.titleInput) this.$refs.titleInput.blur()
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/axios": "^5.13.6",
|
"@nuxtjs/axios": "^5.13.6",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast client",
|
"description": "Self-hosted audiobook and podcast client",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -97,8 +97,8 @@
|
|||||||
<div class="flex justify-center flex-wrap">
|
<div class="flex justify-center flex-wrap">
|
||||||
<template v-for="libraryItem in libraryItemCopies">
|
<template v-for="libraryItem in libraryItemCopies">
|
||||||
<div :key="libraryItem.id" class="w-full max-w-3xl border border-black-300 p-6 -ml-px -mt-px">
|
<div :key="libraryItem.id" class="w-full max-w-3xl border border-black-300 p-6 -ml-px -mt-px">
|
||||||
<widgets-book-details-edit v-if="libraryItem.mediaType === 'book'" :ref="`itemForm-${libraryItem.id}`" :library-item="libraryItem" />
|
<widgets-book-details-edit v-if="libraryItem.mediaType === 'book'" :ref="`itemForm-${libraryItem.id}`" :library-item="libraryItem" @change="handleItemChange" />
|
||||||
<widgets-podcast-details-edit v-else :ref="`itemForm-${libraryItem.id}`" :library-item="libraryItem" />
|
<widgets-podcast-details-edit v-else :ref="`itemForm-${libraryItem.id}`" :library-item="libraryItem" @change="handleItemChange" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
<div :class="isScrollable ? 'fixed left-0 box-shadow-lg-up bg-primary' : ''" class="w-full h-20 px-4 flex items-center border-t border-bg z-40" :style="{ bottom: streamLibraryItem ? '165px' : '0px' }">
|
<div :class="isScrollable ? 'fixed left-0 box-shadow-lg-up bg-primary' : ''" class="w-full h-20 px-4 flex items-center border-t border-bg z-40" :style="{ bottom: streamLibraryItem ? '165px' : '0px' }">
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<ui-btn color="success" :padding-x="8" class="text-lg" :loading="isProcessing" @click.prevent="saveClick">{{ $strings.ButtonSave }}</ui-btn>
|
<ui-btn color="success" :padding-x="8" class="text-lg" :loading="isProcessing" :disabled="!hasChanges" @click.prevent="saveClick">{{ $strings.ButtonSave }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -170,7 +170,8 @@ export default {
|
|||||||
abridged: false
|
abridged: false
|
||||||
},
|
},
|
||||||
appendableKeys: ['authors', 'genres', 'tags', 'narrators', 'series'],
|
appendableKeys: ['authors', 'genres', 'tags', 'narrators', 'series'],
|
||||||
openMapOptions: false
|
openMapOptions: false,
|
||||||
|
itemsWithChanges: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -221,9 +222,19 @@ export default {
|
|||||||
},
|
},
|
||||||
hasSelectedBatchUsage() {
|
hasSelectedBatchUsage() {
|
||||||
return Object.values(this.selectedBatchUsage).some((b) => !!b)
|
return Object.values(this.selectedBatchUsage).some((b) => !!b)
|
||||||
|
},
|
||||||
|
hasChanges() {
|
||||||
|
return this.itemsWithChanges.length > 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleItemChange(itemChange) {
|
||||||
|
if (!itemChange.hasChanges) {
|
||||||
|
this.itemsWithChanges = this.itemsWithChanges.filter((id) => id !== itemChange.libraryItemId)
|
||||||
|
} else if (!this.itemsWithChanges.includes(itemChange.libraryItemId)) {
|
||||||
|
this.itemsWithChanges.push(itemChange.libraryItemId)
|
||||||
|
}
|
||||||
|
},
|
||||||
blurBatchForm() {
|
blurBatchForm() {
|
||||||
if (this.$refs.seriesSelect && this.$refs.seriesSelect.isFocused) {
|
if (this.$refs.seriesSelect && this.$refs.seriesSelect.isFocused) {
|
||||||
this.$refs.seriesSelect.forceBlur()
|
this.$refs.seriesSelect.forceBlur()
|
||||||
@@ -283,38 +294,10 @@ export default {
|
|||||||
removedSeriesItem(item) {},
|
removedSeriesItem(item) {},
|
||||||
newNarratorItem(item) {},
|
newNarratorItem(item) {},
|
||||||
removedNarratorItem(item) {},
|
removedNarratorItem(item) {},
|
||||||
newTagItem(item) {
|
newTagItem(item) {},
|
||||||
// if (item && !this.newTagItems.includes(item)) {
|
removedTagItem(item) {},
|
||||||
// this.newTagItems.push(item)
|
newGenreItem(item) {},
|
||||||
// }
|
removedGenreItem(item) {},
|
||||||
},
|
|
||||||
removedTagItem(item) {
|
|
||||||
// If newly added, remove if not used on any other items
|
|
||||||
// if (item && this.newTagItems.includes(item)) {
|
|
||||||
// var usedByOtherAb = this.libraryItemCopies.find((ab) => {
|
|
||||||
// return ab.tags && ab.tags.includes(item)
|
|
||||||
// })
|
|
||||||
// if (!usedByOtherAb) {
|
|
||||||
// this.newTagItems = this.newTagItems.filter((t) => t !== item)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
newGenreItem(item) {
|
|
||||||
// if (item && !this.newGenreItems.includes(item)) {
|
|
||||||
// this.newGenreItems.push(item)
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
removedGenreItem(item) {
|
|
||||||
// If newly added, remove if not used on any other items
|
|
||||||
// if (item && this.newGenreItems.includes(item)) {
|
|
||||||
// var usedByOtherAb = this.libraryItemCopies.find((ab) => {
|
|
||||||
// return ab.book.genres && ab.book.genres.includes(item)
|
|
||||||
// })
|
|
||||||
// if (!usedByOtherAb) {
|
|
||||||
// this.newGenreItems = this.newGenreItems.filter((t) => t !== item)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
init() {
|
init() {
|
||||||
// TODO: Better deep cloning of library items
|
// TODO: Better deep cloning of library items
|
||||||
this.libraryItemCopies = this.libraryItems.map((li) => {
|
this.libraryItemCopies = this.libraryItems.map((li) => {
|
||||||
@@ -376,6 +359,7 @@ export default {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.isProcessing = false
|
this.isProcessing = false
|
||||||
if (data.updates) {
|
if (data.updates) {
|
||||||
|
this.itemsWithChanges = []
|
||||||
this.$toast.success(`Successfully updated ${data.updates} items`)
|
this.$toast.success(`Successfully updated ${data.updates} items`)
|
||||||
this.$router.replace(`/library/${this.currentLibraryId}/bookshelf`)
|
this.$router.replace(`/library/${this.currentLibraryId}/bookshelf`)
|
||||||
} else {
|
} else {
|
||||||
@@ -387,10 +371,28 @@ export default {
|
|||||||
this.$toast.error('Failed to batch update')
|
this.$toast.error('Failed to batch update')
|
||||||
this.isProcessing = false
|
this.isProcessing = false
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
beforeUnload(e) {
|
||||||
|
if (!e || !this.hasChanges) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.returnValue = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeRouteLeave(to, from, next) {
|
||||||
|
if (this.hasChanges) {
|
||||||
|
next(false)
|
||||||
|
window.location = to.path
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init()
|
this.init()
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', this.beforeUnload)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('beforeunload', this.beforeUnload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+31
-1
@@ -9,6 +9,7 @@
|
|||||||
"ButtonApply": "প্রয়োগ করুন",
|
"ButtonApply": "প্রয়োগ করুন",
|
||||||
"ButtonApplyChapters": "অধ্যায় প্রয়োগ করুন",
|
"ButtonApplyChapters": "অধ্যায় প্রয়োগ করুন",
|
||||||
"ButtonAuthors": "লেখক",
|
"ButtonAuthors": "লেখক",
|
||||||
|
"ButtonBack": "পেছনে যান",
|
||||||
"ButtonBrowseForFolder": "ফোল্ডারের জন্য ব্রাউজ করুন",
|
"ButtonBrowseForFolder": "ফোল্ডারের জন্য ব্রাউজ করুন",
|
||||||
"ButtonCancel": "বাতিল করুন",
|
"ButtonCancel": "বাতিল করুন",
|
||||||
"ButtonCancelEncode": "এনকোড বাতিল করুন",
|
"ButtonCancelEncode": "এনকোড বাতিল করুন",
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
"ButtonChooseFiles": "ফাইল চয়ন করুন",
|
"ButtonChooseFiles": "ফাইল চয়ন করুন",
|
||||||
"ButtonClearFilter": "ফিল্টার পরিষ্কার করুন",
|
"ButtonClearFilter": "ফিল্টার পরিষ্কার করুন",
|
||||||
"ButtonCloseFeed": "ফিড বন্ধ করুন",
|
"ButtonCloseFeed": "ফিড বন্ধ করুন",
|
||||||
|
"ButtonCloseSession": "খোলা সেশন বন্ধ করুন",
|
||||||
"ButtonCollections": "সংগ্রহ",
|
"ButtonCollections": "সংগ্রহ",
|
||||||
"ButtonConfigureScanner": "স্ক্যানার কনফিগার করুন",
|
"ButtonConfigureScanner": "স্ক্যানার কনফিগার করুন",
|
||||||
"ButtonCreate": "তৈরি করুন",
|
"ButtonCreate": "তৈরি করুন",
|
||||||
@@ -27,6 +29,9 @@
|
|||||||
"ButtonEdit": "সম্পাদনা করুন",
|
"ButtonEdit": "সম্পাদনা করুন",
|
||||||
"ButtonEditChapters": "অধ্যায় সম্পাদনা করুন",
|
"ButtonEditChapters": "অধ্যায় সম্পাদনা করুন",
|
||||||
"ButtonEditPodcast": "পডকাস্ট সম্পাদনা করুন",
|
"ButtonEditPodcast": "পডকাস্ট সম্পাদনা করুন",
|
||||||
|
"ButtonEnable": "সক্রিয় করুন",
|
||||||
|
"ButtonFireAndFail": "সক্রিয় এবং ব্যর্থ",
|
||||||
|
"ButtonFireOnTest": "পরীক্ষামূলক ইভেন্টে সক্রিয় করুন",
|
||||||
"ButtonForceReScan": "জোরপূর্বক পুনরায় স্ক্যান করুন",
|
"ButtonForceReScan": "জোরপূর্বক পুনরায় স্ক্যান করুন",
|
||||||
"ButtonFullPath": "সম্পূর্ণ পথ",
|
"ButtonFullPath": "সম্পূর্ণ পথ",
|
||||||
"ButtonHide": "লুকান",
|
"ButtonHide": "লুকান",
|
||||||
@@ -45,6 +50,7 @@
|
|||||||
"ButtonNevermind": "কিছু মনে করবেন না",
|
"ButtonNevermind": "কিছু মনে করবেন না",
|
||||||
"ButtonNext": "পরবর্তী",
|
"ButtonNext": "পরবর্তী",
|
||||||
"ButtonNextChapter": "পরবর্তী অধ্যায়",
|
"ButtonNextChapter": "পরবর্তী অধ্যায়",
|
||||||
|
"ButtonNextItemInQueue": "সারিতে পরের আইটেম",
|
||||||
"ButtonOk": "ঠিক আছে",
|
"ButtonOk": "ঠিক আছে",
|
||||||
"ButtonOpenFeed": "ফিড খুলুন",
|
"ButtonOpenFeed": "ফিড খুলুন",
|
||||||
"ButtonOpenManager": "ম্যানেজার খুলুন",
|
"ButtonOpenManager": "ম্যানেজার খুলুন",
|
||||||
@@ -54,13 +60,17 @@
|
|||||||
"ButtonPlaylists": "প্লেলিস্ট",
|
"ButtonPlaylists": "প্লেলিস্ট",
|
||||||
"ButtonPrevious": "পূর্ববর্তী",
|
"ButtonPrevious": "পূর্ববর্তী",
|
||||||
"ButtonPreviousChapter": "আগের অধ্যায়",
|
"ButtonPreviousChapter": "আগের অধ্যায়",
|
||||||
|
"ButtonProbeAudioFile": "প্রোব অডিও ফাইল",
|
||||||
"ButtonPurgeAllCache": "সমস্ত ক্যাশে পরিষ্কার করুন",
|
"ButtonPurgeAllCache": "সমস্ত ক্যাশে পরিষ্কার করুন",
|
||||||
"ButtonPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কার করুন",
|
"ButtonPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কার করুন",
|
||||||
"ButtonQueueAddItem": "সারিতে যোগ করুন",
|
"ButtonQueueAddItem": "সারিতে যোগ করুন",
|
||||||
"ButtonQueueRemoveItem": "সারি থেকে মুছে ফেলুন",
|
"ButtonQueueRemoveItem": "সারি থেকে মুছে ফেলুন",
|
||||||
|
"ButtonQuickEmbedMetadata": "মেটাডেটা দ্রুত এম্বেড করুন",
|
||||||
"ButtonQuickMatch": "দ্রুত ম্যাচ",
|
"ButtonQuickMatch": "দ্রুত ম্যাচ",
|
||||||
"ButtonReScan": "পুনরায় স্ক্যান",
|
"ButtonReScan": "পুনরায় স্ক্যান",
|
||||||
"ButtonRead": "পড়ুন",
|
"ButtonRead": "পড়ুন",
|
||||||
|
"ButtonReadLess": "সংক্ষিপ্ত",
|
||||||
|
"ButtonReadMore": "বিস্তারিত পড়ুন",
|
||||||
"ButtonRefresh": "রিফ্রেশ",
|
"ButtonRefresh": "রিফ্রেশ",
|
||||||
"ButtonRemove": "মুছে ফেলুন",
|
"ButtonRemove": "মুছে ফেলুন",
|
||||||
"ButtonRemoveAll": "সব মুছে ফেলুন",
|
"ButtonRemoveAll": "সব মুছে ফেলুন",
|
||||||
@@ -85,6 +95,7 @@
|
|||||||
"ButtonShow": "দেখান",
|
"ButtonShow": "দেখান",
|
||||||
"ButtonStartM4BEncode": "M4B এনকোড শুরু করুন",
|
"ButtonStartM4BEncode": "M4B এনকোড শুরু করুন",
|
||||||
"ButtonStartMetadataEmbed": "মেটাডেটা এম্বেড শুরু করুন",
|
"ButtonStartMetadataEmbed": "মেটাডেটা এম্বেড শুরু করুন",
|
||||||
|
"ButtonStats": "পরিসংখ্যান",
|
||||||
"ButtonSubmit": "জমা দিন",
|
"ButtonSubmit": "জমা দিন",
|
||||||
"ButtonTest": "পরীক্ষা",
|
"ButtonTest": "পরীক্ষা",
|
||||||
"ButtonUpload": "আপলোড",
|
"ButtonUpload": "আপলোড",
|
||||||
@@ -99,9 +110,10 @@
|
|||||||
"ErrorUploadFetchMetadataNoResults": "মেটাডেটা আনা যায়নি - শিরোনাম এবং/অথবা লেখক আপডেট করার চেষ্টা করুন",
|
"ErrorUploadFetchMetadataNoResults": "মেটাডেটা আনা যায়নি - শিরোনাম এবং/অথবা লেখক আপডেট করার চেষ্টা করুন",
|
||||||
"ErrorUploadLacksTitle": "একটি শিরোনাম থাকতে হবে",
|
"ErrorUploadLacksTitle": "একটি শিরোনাম থাকতে হবে",
|
||||||
"HeaderAccount": "অ্যাকাউন্ট",
|
"HeaderAccount": "অ্যাকাউন্ট",
|
||||||
|
"HeaderAddCustomMetadataProvider": "কাস্টম মেটাডেটা সরবরাহকারী যোগ করুন",
|
||||||
"HeaderAdvanced": "অ্যাডভান্সড",
|
"HeaderAdvanced": "অ্যাডভান্সড",
|
||||||
"HeaderAppriseNotificationSettings": "বিজ্ঞপ্তি সেটিংস অবহিত করুন",
|
"HeaderAppriseNotificationSettings": "বিজ্ঞপ্তি সেটিংস অবহিত করুন",
|
||||||
"HeaderAudioTracks": "অডিও ট্র্যাকস",
|
"HeaderAudioTracks": "অডিও ট্র্যাকসগুলো",
|
||||||
"HeaderAudiobookTools": "অডিওবই ফাইল ম্যানেজমেন্ট টুলস",
|
"HeaderAudiobookTools": "অডিওবই ফাইল ম্যানেজমেন্ট টুলস",
|
||||||
"HeaderAuthentication": "প্রমাণীকরণ",
|
"HeaderAuthentication": "প্রমাণীকরণ",
|
||||||
"HeaderBackups": "ব্যাকআপ",
|
"HeaderBackups": "ব্যাকআপ",
|
||||||
@@ -112,6 +124,7 @@
|
|||||||
"HeaderCollectionItems": "সংগ্রহ আইটেম",
|
"HeaderCollectionItems": "সংগ্রহ আইটেম",
|
||||||
"HeaderCover": "কভার",
|
"HeaderCover": "কভার",
|
||||||
"HeaderCurrentDownloads": "বর্তমান ডাউনলোডগুলি",
|
"HeaderCurrentDownloads": "বর্তমান ডাউনলোডগুলি",
|
||||||
|
"HeaderCustomMessageOnLogin": "লগইন এ কাস্টম বার্তা",
|
||||||
"HeaderCustomMetadataProviders": "কাস্টম মেটাডেটা প্রদানকারী",
|
"HeaderCustomMetadataProviders": "কাস্টম মেটাডেটা প্রদানকারী",
|
||||||
"HeaderDetails": "বিস্তারিত",
|
"HeaderDetails": "বিস্তারিত",
|
||||||
"HeaderDownloadQueue": "ডাউনলোড সারি",
|
"HeaderDownloadQueue": "ডাউনলোড সারি",
|
||||||
@@ -143,6 +156,8 @@
|
|||||||
"HeaderMetadataToEmbed": "এম্বেড করার জন্য মেটাডেটা",
|
"HeaderMetadataToEmbed": "এম্বেড করার জন্য মেটাডেটা",
|
||||||
"HeaderNewAccount": "নতুন অ্যাকাউন্ট",
|
"HeaderNewAccount": "নতুন অ্যাকাউন্ট",
|
||||||
"HeaderNewLibrary": "নতুন লাইব্রেরি",
|
"HeaderNewLibrary": "নতুন লাইব্রেরি",
|
||||||
|
"HeaderNotificationCreate": "বিজ্ঞপ্তি তৈরি করুন",
|
||||||
|
"HeaderNotificationUpdate": "বিজ্ঞপ্তি আপডেট করুন",
|
||||||
"HeaderNotifications": "বিজ্ঞপ্তি",
|
"HeaderNotifications": "বিজ্ঞপ্তি",
|
||||||
"HeaderOpenIDConnectAuthentication": "ওপেনআইডি সংযোগ প্রমাণীকরণ",
|
"HeaderOpenIDConnectAuthentication": "ওপেনআইডি সংযোগ প্রমাণীকরণ",
|
||||||
"HeaderOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
"HeaderOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
||||||
@@ -150,6 +165,7 @@
|
|||||||
"HeaderPasswordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
"HeaderPasswordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
||||||
"HeaderPermissions": "অনুমতি",
|
"HeaderPermissions": "অনুমতি",
|
||||||
"HeaderPlayerQueue": "প্লেয়ার সারি",
|
"HeaderPlayerQueue": "প্লেয়ার সারি",
|
||||||
|
"HeaderPlayerSettings": "প্লেয়ার সেটিংস",
|
||||||
"HeaderPlaylist": "প্লেলিস্ট",
|
"HeaderPlaylist": "প্লেলিস্ট",
|
||||||
"HeaderPlaylistItems": "প্লেলিস্ট আইটেম",
|
"HeaderPlaylistItems": "প্লেলিস্ট আইটেম",
|
||||||
"HeaderPodcastsToAdd": "যোগ করার জন্য পডকাস্ট",
|
"HeaderPodcastsToAdd": "যোগ করার জন্য পডকাস্ট",
|
||||||
@@ -186,6 +202,9 @@
|
|||||||
"HeaderYearReview": "বাৎসরিক পর্যালোচনা {0}",
|
"HeaderYearReview": "বাৎসরিক পর্যালোচনা {0}",
|
||||||
"HeaderYourStats": "আপনার পরিসংখ্যান",
|
"HeaderYourStats": "আপনার পরিসংখ্যান",
|
||||||
"LabelAbridged": "সংক্ষিপ্ত",
|
"LabelAbridged": "সংক্ষিপ্ত",
|
||||||
|
"LabelAbridgedChecked": "সংক্ষিপ্ত (চেক)",
|
||||||
|
"LabelAbridgedUnchecked": "অসংক্ষেপিত (চেক করা হয়নি)",
|
||||||
|
"LabelAccessibleBy": "দ্বারা প্রবেশযোগ্য",
|
||||||
"LabelAccountType": "অ্যাকাউন্টের প্রকার",
|
"LabelAccountType": "অ্যাকাউন্টের প্রকার",
|
||||||
"LabelAccountTypeAdmin": "প্রশাসন",
|
"LabelAccountTypeAdmin": "প্রশাসন",
|
||||||
"LabelAccountTypeGuest": "অতিথি",
|
"LabelAccountTypeGuest": "অতিথি",
|
||||||
@@ -196,6 +215,7 @@
|
|||||||
"LabelAddToPlaylist": "প্লেলিস্টে যোগ করুন",
|
"LabelAddToPlaylist": "প্লেলিস্টে যোগ করুন",
|
||||||
"LabelAddToPlaylistBatch": "প্লেলিস্টে {0}টি আইটেম যোগ করুন",
|
"LabelAddToPlaylistBatch": "প্লেলিস্টে {0}টি আইটেম যোগ করুন",
|
||||||
"LabelAddedAt": "এতে যোগ করা হয়েছে",
|
"LabelAddedAt": "এতে যোগ করা হয়েছে",
|
||||||
|
"LabelAddedDate": "যোগ করা হয়েছে {0}",
|
||||||
"LabelAdminUsersOnly": "শুধু অ্যাডমিন ব্যবহারকারী",
|
"LabelAdminUsersOnly": "শুধু অ্যাডমিন ব্যবহারকারী",
|
||||||
"LabelAll": "সব",
|
"LabelAll": "সব",
|
||||||
"LabelAllUsers": "সমস্ত ব্যবহারকারী",
|
"LabelAllUsers": "সমস্ত ব্যবহারকারী",
|
||||||
@@ -225,6 +245,7 @@
|
|||||||
"LabelBitrate": "বিটরেট",
|
"LabelBitrate": "বিটরেট",
|
||||||
"LabelBooks": "বইগুলো",
|
"LabelBooks": "বইগুলো",
|
||||||
"LabelButtonText": "ঘর পাঠ্য",
|
"LabelButtonText": "ঘর পাঠ্য",
|
||||||
|
"LabelByAuthor": "দ্বারা {0}",
|
||||||
"LabelChangePassword": "পাসওয়ার্ড পরিবর্তন করুন",
|
"LabelChangePassword": "পাসওয়ার্ড পরিবর্তন করুন",
|
||||||
"LabelChannels": "চ্যানেল",
|
"LabelChannels": "চ্যানেল",
|
||||||
"LabelChapterTitle": "অধ্যায়ের শিরোনাম",
|
"LabelChapterTitle": "অধ্যায়ের শিরোনাম",
|
||||||
@@ -234,6 +255,7 @@
|
|||||||
"LabelClosePlayer": "প্লেয়ার বন্ধ করুন",
|
"LabelClosePlayer": "প্লেয়ার বন্ধ করুন",
|
||||||
"LabelCodec": "কোডেক",
|
"LabelCodec": "কোডেক",
|
||||||
"LabelCollapseSeries": "সিরিজ সঙ্কুচিত করুন",
|
"LabelCollapseSeries": "সিরিজ সঙ্কুচিত করুন",
|
||||||
|
"LabelCollapseSubSeries": "উপ-সিরিজ সঙ্কুচিত করুন",
|
||||||
"LabelCollection": "সংগ্রহ",
|
"LabelCollection": "সংগ্রহ",
|
||||||
"LabelCollections": "সংগ্রহ",
|
"LabelCollections": "সংগ্রহ",
|
||||||
"LabelComplete": "সম্পূর্ণ",
|
"LabelComplete": "সম্পূর্ণ",
|
||||||
@@ -249,6 +271,7 @@
|
|||||||
"LabelCurrently": "বর্তমানে:",
|
"LabelCurrently": "বর্তমানে:",
|
||||||
"LabelCustomCronExpression": "কাস্টম Cron এক্সপ্রেশন:",
|
"LabelCustomCronExpression": "কাস্টম Cron এক্সপ্রেশন:",
|
||||||
"LabelDatetime": "তারিখ সময়",
|
"LabelDatetime": "তারিখ সময়",
|
||||||
|
"LabelDays": "দিনগুলো",
|
||||||
"LabelDeleteFromFileSystemCheckbox": "ফাইল সিস্টেম থেকে মুছে ফেলুন (শুধু ডাটাবেস থেকে সরাতে টিক চিহ্ন মুক্ত করুন)",
|
"LabelDeleteFromFileSystemCheckbox": "ফাইল সিস্টেম থেকে মুছে ফেলুন (শুধু ডাটাবেস থেকে সরাতে টিক চিহ্ন মুক্ত করুন)",
|
||||||
"LabelDescription": "বিবরণ",
|
"LabelDescription": "বিবরণ",
|
||||||
"LabelDeselectAll": "সমস্ত অনির্বাচিত করুন",
|
"LabelDeselectAll": "সমস্ত অনির্বাচিত করুন",
|
||||||
@@ -262,12 +285,16 @@
|
|||||||
"LabelDownload": "ডাউনলোড করুন",
|
"LabelDownload": "ডাউনলোড করুন",
|
||||||
"LabelDownloadNEpisodes": "{0}টি পর্ব ডাউনলোড করুন",
|
"LabelDownloadNEpisodes": "{0}টি পর্ব ডাউনলোড করুন",
|
||||||
"LabelDuration": "সময়কাল",
|
"LabelDuration": "সময়কাল",
|
||||||
|
"LabelDurationComparisonExactMatch": "(সঠিক মিল)",
|
||||||
|
"LabelDurationComparisonLonger": "({0} দীর্ঘ)",
|
||||||
|
"LabelDurationComparisonShorter": "({0} ছোট)",
|
||||||
"LabelDurationFound": "সময়কাল পাওয়া গেছে:",
|
"LabelDurationFound": "সময়কাল পাওয়া গেছে:",
|
||||||
"LabelEbook": "ই-বই",
|
"LabelEbook": "ই-বই",
|
||||||
"LabelEbooks": "ই-বইগুলো",
|
"LabelEbooks": "ই-বইগুলো",
|
||||||
"LabelEdit": "সম্পাদনা করুন",
|
"LabelEdit": "সম্পাদনা করুন",
|
||||||
"LabelEmail": "ইমেইল",
|
"LabelEmail": "ইমেইল",
|
||||||
"LabelEmailSettingsFromAddress": "ঠিকানা থেকে",
|
"LabelEmailSettingsFromAddress": "ঠিকানা থেকে",
|
||||||
|
"LabelEmailSettingsRejectUnauthorized": "অননুমোদিত সার্টিফিকেট প্রত্যাখ্যান করুন",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Disabling SSL certificate validation may expose your connection to security risks, such as man-in-the-middle attacks. Only disable this option if you understand the implications and trust the mail server you are connecting to।",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Disabling SSL certificate validation may expose your connection to security risks, such as man-in-the-middle attacks. Only disable this option if you understand the implications and trust the mail server you are connecting to।",
|
||||||
"LabelEmailSettingsSecure": "নিরাপদ",
|
"LabelEmailSettingsSecure": "নিরাপদ",
|
||||||
"LabelEmailSettingsSecureHelp": "যদি সত্য হয় সার্ভারের সাথে সংযোগ করার সময় সংযোগটি TLS ব্যবহার করবে। মিথ্যা হলে TLS ব্যবহার করা হবে যদি সার্ভার STARTTLS এক্সটেনশন সমর্থন করে। বেশিরভাগ ক্ষেত্রে এই মানটিকে সত্য হিসাবে সেট করুন যদি আপনি পোর্ট 465-এর সাথে সংযোগ করছেন। পোর্ট 587 বা পোর্টের জন্য 25 এটি মিথ্যা রাখুন। (nodemailer.com/smtp/#authentication থেকে)",
|
"LabelEmailSettingsSecureHelp": "যদি সত্য হয় সার্ভারের সাথে সংযোগ করার সময় সংযোগটি TLS ব্যবহার করবে। মিথ্যা হলে TLS ব্যবহার করা হবে যদি সার্ভার STARTTLS এক্সটেনশন সমর্থন করে। বেশিরভাগ ক্ষেত্রে এই মানটিকে সত্য হিসাবে সেট করুন যদি আপনি পোর্ট 465-এর সাথে সংযোগ করছেন। পোর্ট 587 বা পোর্টের জন্য 25 এটি মিথ্যা রাখুন। (nodemailer.com/smtp/#authentication থেকে)",
|
||||||
@@ -275,10 +302,13 @@
|
|||||||
"LabelEmbeddedCover": "এম্বেডেড কভার",
|
"LabelEmbeddedCover": "এম্বেডেড কভার",
|
||||||
"LabelEnable": "সক্ষম করুন",
|
"LabelEnable": "সক্ষম করুন",
|
||||||
"LabelEnd": "সমাপ্ত",
|
"LabelEnd": "সমাপ্ত",
|
||||||
|
"LabelEndOfChapter": "অধ্যায়ের সমাপ্তি",
|
||||||
"LabelEpisode": "পর্ব",
|
"LabelEpisode": "পর্ব",
|
||||||
"LabelEpisodeTitle": "পর্বের শিরোনাম",
|
"LabelEpisodeTitle": "পর্বের শিরোনাম",
|
||||||
"LabelEpisodeType": "পর্বের ধরন",
|
"LabelEpisodeType": "পর্বের ধরন",
|
||||||
|
"LabelEpisodes": "পর্বগুলো",
|
||||||
"LabelExample": "উদাহরণ",
|
"LabelExample": "উদাহরণ",
|
||||||
|
"LabelExpandSeries": "সিরিজ প্রসারিত করুন",
|
||||||
"LabelExplicit": "বিশদ",
|
"LabelExplicit": "বিশদ",
|
||||||
"LabelFeedURL": "ফিড ইউআরএল",
|
"LabelFeedURL": "ফিড ইউআরএল",
|
||||||
"LabelFetchingMetadata": "মেটাডেটা আনা হচ্ছে",
|
"LabelFetchingMetadata": "মেটাডেটা আনা হচ্ছে",
|
||||||
|
|||||||
@@ -98,7 +98,6 @@
|
|||||||
"ButtonStats": "Statistiken",
|
"ButtonStats": "Statistiken",
|
||||||
"ButtonSubmit": "Ok",
|
"ButtonSubmit": "Ok",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpedId": "OpenID trennen",
|
|
||||||
"ButtonUpload": "Hochladen",
|
"ButtonUpload": "Hochladen",
|
||||||
"ButtonUploadBackup": "Sicherung hochladen",
|
"ButtonUploadBackup": "Sicherung hochladen",
|
||||||
"ButtonUploadCover": "Titelbild hochladen",
|
"ButtonUploadCover": "Titelbild hochladen",
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
"ButtonStats": "Stats",
|
"ButtonStats": "Stats",
|
||||||
"ButtonSubmit": "Submit",
|
"ButtonSubmit": "Submit",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpedId": "Unlink OpenID",
|
"ButtonUnlinkOpenId": "Unlink OpenID",
|
||||||
"ButtonUpload": "Upload",
|
"ButtonUpload": "Upload",
|
||||||
"ButtonUploadBackup": "Upload Backup",
|
"ButtonUploadBackup": "Upload Backup",
|
||||||
"ButtonUploadCover": "Upload Cover",
|
"ButtonUploadCover": "Upload Cover",
|
||||||
|
|||||||
@@ -97,7 +97,6 @@
|
|||||||
"ButtonStats": "Estadísticas",
|
"ButtonStats": "Estadísticas",
|
||||||
"ButtonSubmit": "Enviar",
|
"ButtonSubmit": "Enviar",
|
||||||
"ButtonTest": "Prueba",
|
"ButtonTest": "Prueba",
|
||||||
"ButtonUnlinkOpedId": "Desvincular OpenID",
|
|
||||||
"ButtonUpload": "Subir",
|
"ButtonUpload": "Subir",
|
||||||
"ButtonUploadBackup": "Subir Respaldo",
|
"ButtonUploadBackup": "Subir Respaldo",
|
||||||
"ButtonUploadCover": "Subir Portada",
|
"ButtonUploadCover": "Subir Portada",
|
||||||
|
|||||||
@@ -98,7 +98,6 @@
|
|||||||
"ButtonStats": "Statistiques",
|
"ButtonStats": "Statistiques",
|
||||||
"ButtonSubmit": "Soumettre",
|
"ButtonSubmit": "Soumettre",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpedId": "Dissocier OpenID",
|
|
||||||
"ButtonUpload": "Téléverser",
|
"ButtonUpload": "Téléverser",
|
||||||
"ButtonUploadBackup": "Téléverser une sauvegarde",
|
"ButtonUploadBackup": "Téléverser une sauvegarde",
|
||||||
"ButtonUploadCover": "Téléverser une couverture",
|
"ButtonUploadCover": "Téléverser une couverture",
|
||||||
|
|||||||
@@ -98,7 +98,6 @@
|
|||||||
"ButtonStats": "Statistika",
|
"ButtonStats": "Statistika",
|
||||||
"ButtonSubmit": "Podnesi",
|
"ButtonSubmit": "Podnesi",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpedId": "Odspoji OpenID",
|
|
||||||
"ButtonUpload": "Učitaj",
|
"ButtonUpload": "Učitaj",
|
||||||
"ButtonUploadBackup": "Učitaj sigurnosnu kopiju",
|
"ButtonUploadBackup": "Učitaj sigurnosnu kopiju",
|
||||||
"ButtonUploadCover": "Učitaj naslovnicu",
|
"ButtonUploadCover": "Učitaj naslovnicu",
|
||||||
|
|||||||
+38
-1
@@ -19,6 +19,7 @@
|
|||||||
"ButtonChooseFiles": "Wybierz pliki",
|
"ButtonChooseFiles": "Wybierz pliki",
|
||||||
"ButtonClearFilter": "Wyczyść filtr",
|
"ButtonClearFilter": "Wyczyść filtr",
|
||||||
"ButtonCloseFeed": "Zamknij kanał",
|
"ButtonCloseFeed": "Zamknij kanał",
|
||||||
|
"ButtonCloseSession": "Zamknij otwartą sesję",
|
||||||
"ButtonCollections": "Kolekcje",
|
"ButtonCollections": "Kolekcje",
|
||||||
"ButtonConfigureScanner": "Skonfiguruj skaner",
|
"ButtonConfigureScanner": "Skonfiguruj skaner",
|
||||||
"ButtonCreate": "Utwórz",
|
"ButtonCreate": "Utwórz",
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
"ButtonEdit": "Edycja",
|
"ButtonEdit": "Edycja",
|
||||||
"ButtonEditChapters": "Edytuj rozdziały",
|
"ButtonEditChapters": "Edytuj rozdziały",
|
||||||
"ButtonEditPodcast": "Edytuj podcast",
|
"ButtonEditPodcast": "Edytuj podcast",
|
||||||
|
"ButtonEnable": "Włącz",
|
||||||
"ButtonForceReScan": "Wymuś ponowne skanowanie",
|
"ButtonForceReScan": "Wymuś ponowne skanowanie",
|
||||||
"ButtonFullPath": "Pełna ścieżka",
|
"ButtonFullPath": "Pełna ścieżka",
|
||||||
"ButtonHide": "Ukryj",
|
"ButtonHide": "Ukryj",
|
||||||
@@ -47,8 +49,10 @@
|
|||||||
"ButtonNext": "Następny",
|
"ButtonNext": "Następny",
|
||||||
"ButtonNextChapter": "Następny rozdział",
|
"ButtonNextChapter": "Następny rozdział",
|
||||||
"ButtonNextItemInQueue": "Następny element w kolejce",
|
"ButtonNextItemInQueue": "Następny element w kolejce",
|
||||||
|
"ButtonOk": "Ok",
|
||||||
"ButtonOpenFeed": "Otwórz feed",
|
"ButtonOpenFeed": "Otwórz feed",
|
||||||
"ButtonOpenManager": "Otwórz menadżera",
|
"ButtonOpenManager": "Otwórz menadżera",
|
||||||
|
"ButtonPause": "Wstrzymaj",
|
||||||
"ButtonPlay": "Odtwarzaj",
|
"ButtonPlay": "Odtwarzaj",
|
||||||
"ButtonPlaying": "Odtwarzane",
|
"ButtonPlaying": "Odtwarzane",
|
||||||
"ButtonPlaylists": "Listy odtwarzania",
|
"ButtonPlaylists": "Listy odtwarzania",
|
||||||
@@ -90,6 +94,7 @@
|
|||||||
"ButtonStartMetadataEmbed": "Osadź metadane",
|
"ButtonStartMetadataEmbed": "Osadź metadane",
|
||||||
"ButtonStats": "Statystyki",
|
"ButtonStats": "Statystyki",
|
||||||
"ButtonSubmit": "Zaloguj",
|
"ButtonSubmit": "Zaloguj",
|
||||||
|
"ButtonTest": "Test",
|
||||||
"ButtonUpload": "Wgraj",
|
"ButtonUpload": "Wgraj",
|
||||||
"ButtonUploadBackup": "Wgraj kopię zapasową",
|
"ButtonUploadBackup": "Wgraj kopię zapasową",
|
||||||
"ButtonUploadCover": "Wgraj okładkę",
|
"ButtonUploadCover": "Wgraj okładkę",
|
||||||
@@ -102,6 +107,7 @@
|
|||||||
"ErrorUploadFetchMetadataNoResults": "Nie można pobrać metadanych — spróbuj zaktualizować tytuł i/lub autora",
|
"ErrorUploadFetchMetadataNoResults": "Nie można pobrać metadanych — spróbuj zaktualizować tytuł i/lub autora",
|
||||||
"ErrorUploadLacksTitle": "Musi mieć tytuł",
|
"ErrorUploadLacksTitle": "Musi mieć tytuł",
|
||||||
"HeaderAccount": "Konto",
|
"HeaderAccount": "Konto",
|
||||||
|
"HeaderAddCustomMetadataProvider": "Dodaj niestandardowego dostawcę metadanych",
|
||||||
"HeaderAdvanced": "Zaawansowane",
|
"HeaderAdvanced": "Zaawansowane",
|
||||||
"HeaderAppriseNotificationSettings": "Ustawienia powiadomień Apprise",
|
"HeaderAppriseNotificationSettings": "Ustawienia powiadomień Apprise",
|
||||||
"HeaderAudioTracks": "Ścieżki audio",
|
"HeaderAudioTracks": "Ścieżki audio",
|
||||||
@@ -120,6 +126,7 @@
|
|||||||
"HeaderDetails": "Szczegóły",
|
"HeaderDetails": "Szczegóły",
|
||||||
"HeaderDownloadQueue": "Kolejka do ściągania",
|
"HeaderDownloadQueue": "Kolejka do ściągania",
|
||||||
"HeaderEbookFiles": "Pliki Ebook",
|
"HeaderEbookFiles": "Pliki Ebook",
|
||||||
|
"HeaderEmail": "E-mail",
|
||||||
"HeaderEmailSettings": "Ustawienia e-mail",
|
"HeaderEmailSettings": "Ustawienia e-mail",
|
||||||
"HeaderEpisodes": "Rozdziały",
|
"HeaderEpisodes": "Rozdziały",
|
||||||
"HeaderEreaderDevices": "Czytniki",
|
"HeaderEreaderDevices": "Czytniki",
|
||||||
@@ -145,6 +152,8 @@
|
|||||||
"HeaderMetadataToEmbed": "Osadź metadane",
|
"HeaderMetadataToEmbed": "Osadź metadane",
|
||||||
"HeaderNewAccount": "Nowe konto",
|
"HeaderNewAccount": "Nowe konto",
|
||||||
"HeaderNewLibrary": "Nowa biblioteka",
|
"HeaderNewLibrary": "Nowa biblioteka",
|
||||||
|
"HeaderNotificationCreate": "Utwórz powiadomienie",
|
||||||
|
"HeaderNotificationUpdate": "Zaktualizuj powiadomienie",
|
||||||
"HeaderNotifications": "Powiadomienia",
|
"HeaderNotifications": "Powiadomienia",
|
||||||
"HeaderOpenIDConnectAuthentication": "Uwierzytelnianie OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Uwierzytelnianie OpenID Connect",
|
||||||
"HeaderOpenRSSFeed": "Utwórz kanał RSS",
|
"HeaderOpenRSSFeed": "Utwórz kanał RSS",
|
||||||
@@ -157,7 +166,9 @@
|
|||||||
"HeaderPlaylistItems": "Pozycje listy odtwarzania",
|
"HeaderPlaylistItems": "Pozycje listy odtwarzania",
|
||||||
"HeaderPodcastsToAdd": "Podcasty do dodania",
|
"HeaderPodcastsToAdd": "Podcasty do dodania",
|
||||||
"HeaderPreviewCover": "Podgląd okładki",
|
"HeaderPreviewCover": "Podgląd okładki",
|
||||||
|
"HeaderRSSFeedGeneral": "Szczegóły RSS",
|
||||||
"HeaderRSSFeedIsOpen": "Kanał RSS jest otwarty",
|
"HeaderRSSFeedIsOpen": "Kanał RSS jest otwarty",
|
||||||
|
"HeaderRSSFeeds": "Kanały RSS",
|
||||||
"HeaderRemoveEpisode": "Usuń odcinek",
|
"HeaderRemoveEpisode": "Usuń odcinek",
|
||||||
"HeaderRemoveEpisodes": "Usuń {0} odcinków",
|
"HeaderRemoveEpisodes": "Usuń {0} odcinków",
|
||||||
"HeaderSavedMediaProgress": "Zapisany postęp",
|
"HeaderSavedMediaProgress": "Zapisany postęp",
|
||||||
@@ -200,6 +211,7 @@
|
|||||||
"LabelAddToPlaylist": "Dodaj do playlisty",
|
"LabelAddToPlaylist": "Dodaj do playlisty",
|
||||||
"LabelAddToPlaylistBatch": "Dodaj {0} pozycji do playlisty",
|
"LabelAddToPlaylistBatch": "Dodaj {0} pozycji do playlisty",
|
||||||
"LabelAddedAt": "Dodano",
|
"LabelAddedAt": "Dodano",
|
||||||
|
"LabelAddedDate": "Dodano {0}",
|
||||||
"LabelAdminUsersOnly": "Tylko użytkownicy administracyjni",
|
"LabelAdminUsersOnly": "Tylko użytkownicy administracyjni",
|
||||||
"LabelAll": "Wszystkie",
|
"LabelAll": "Wszystkie",
|
||||||
"LabelAllUsers": "Wszyscy użytkownicy",
|
"LabelAllUsers": "Wszyscy użytkownicy",
|
||||||
@@ -215,15 +227,19 @@
|
|||||||
"LabelAutoFetchMetadata": "Automatycznie pobierz metadane",
|
"LabelAutoFetchMetadata": "Automatycznie pobierz metadane",
|
||||||
"LabelAutoFetchMetadataHelp": "Pobiera metadane dotyczące tytułu, autora i serii, aby usprawnić przesyłanie. Po przesłaniu może być konieczne dopasowanie dodatkowych metadanych.",
|
"LabelAutoFetchMetadataHelp": "Pobiera metadane dotyczące tytułu, autora i serii, aby usprawnić przesyłanie. Po przesłaniu może być konieczne dopasowanie dodatkowych metadanych.",
|
||||||
"LabelAutoLaunch": "Uruchom automatycznie",
|
"LabelAutoLaunch": "Uruchom automatycznie",
|
||||||
|
"LabelAutoRegister": "Automatyczna rejestracja",
|
||||||
|
"LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu",
|
||||||
"LabelBackToUser": "Powrót",
|
"LabelBackToUser": "Powrót",
|
||||||
"LabelBackupLocation": "Lokalizacja kopii zapasowej",
|
"LabelBackupLocation": "Lokalizacja kopii zapasowej",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe",
|
"LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Kopie zapasowe są zapisywane w folderze /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Kopie zapasowe są zapisywane w folderze /metadata/backups",
|
||||||
"LabelBackupsMaxBackupSize": "Maksymalny rozmiar kopii zapasowej (w GB)",
|
"LabelBackupsMaxBackupSize": "Maksymalny rozmiar kopii zapasowej (w GB) (0 oznacza nieograniczony)",
|
||||||
"LabelBackupsMaxBackupSizeHelp": "Jako zabezpieczenie przed błędną konfiguracją, kopie zapasowe nie będą wykonywane, jeśli przekroczą skonfigurowany rozmiar.",
|
"LabelBackupsMaxBackupSizeHelp": "Jako zabezpieczenie przed błędną konfiguracją, kopie zapasowe nie będą wykonywane, jeśli przekroczą skonfigurowany rozmiar.",
|
||||||
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
|
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
|
||||||
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
|
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
"LabelBooks": "Książki",
|
"LabelBooks": "Książki",
|
||||||
|
"LabelButtonText": "Tekst przycisku",
|
||||||
"LabelByAuthor": "autorstwa {0}",
|
"LabelByAuthor": "autorstwa {0}",
|
||||||
"LabelChangePassword": "Zmień hasło",
|
"LabelChangePassword": "Zmień hasło",
|
||||||
"LabelChannels": "Kanały",
|
"LabelChannels": "Kanały",
|
||||||
@@ -232,6 +248,7 @@
|
|||||||
"LabelChaptersFound": "Znalezione rozdziały",
|
"LabelChaptersFound": "Znalezione rozdziały",
|
||||||
"LabelClickForMoreInfo": "Kliknij po więcej szczegółów",
|
"LabelClickForMoreInfo": "Kliknij po więcej szczegółów",
|
||||||
"LabelClosePlayer": "Zamknij odtwarzacz",
|
"LabelClosePlayer": "Zamknij odtwarzacz",
|
||||||
|
"LabelCodec": "Kodek",
|
||||||
"LabelCollapseSeries": "Podsumuj serię",
|
"LabelCollapseSeries": "Podsumuj serię",
|
||||||
"LabelCollapseSubSeries": "Zwiń podserie",
|
"LabelCollapseSubSeries": "Zwiń podserie",
|
||||||
"LabelCollection": "Kolekcja",
|
"LabelCollection": "Kolekcja",
|
||||||
@@ -247,6 +264,7 @@
|
|||||||
"LabelCronExpression": "Wyrażenie CRON",
|
"LabelCronExpression": "Wyrażenie CRON",
|
||||||
"LabelCurrent": "Aktualny",
|
"LabelCurrent": "Aktualny",
|
||||||
"LabelCurrently": "Obecnie:",
|
"LabelCurrently": "Obecnie:",
|
||||||
|
"LabelCustomCronExpression": "Niestandardowe wyrażenie Cron:",
|
||||||
"LabelDatetime": "Data i godzina",
|
"LabelDatetime": "Data i godzina",
|
||||||
"LabelDays": "Dni",
|
"LabelDays": "Dni",
|
||||||
"LabelDeleteFromFileSystemCheckbox": "Usuń z systemu plików (odznacz, aby usunąć tylko z bazy danych)",
|
"LabelDeleteFromFileSystemCheckbox": "Usuń z systemu plików (odznacz, aby usunąć tylko z bazy danych)",
|
||||||
@@ -254,6 +272,7 @@
|
|||||||
"LabelDeselectAll": "Odznacz wszystko",
|
"LabelDeselectAll": "Odznacz wszystko",
|
||||||
"LabelDevice": "Urządzenie",
|
"LabelDevice": "Urządzenie",
|
||||||
"LabelDeviceInfo": "Informacja o urządzeniu",
|
"LabelDeviceInfo": "Informacja o urządzeniu",
|
||||||
|
"LabelDeviceIsAvailableTo": "Urządzenie jest dostępne do...",
|
||||||
"LabelDirectory": "Katalog",
|
"LabelDirectory": "Katalog",
|
||||||
"LabelDiscFromFilename": "Oznaczenie dysku z nazwy pliku",
|
"LabelDiscFromFilename": "Oznaczenie dysku z nazwy pliku",
|
||||||
"LabelDiscFromMetadata": "Oznaczenie dysku z metadanych",
|
"LabelDiscFromMetadata": "Oznaczenie dysku z metadanych",
|
||||||
@@ -261,16 +280,20 @@
|
|||||||
"LabelDownload": "Pobierz",
|
"LabelDownload": "Pobierz",
|
||||||
"LabelDownloadNEpisodes": "Ściąganie {0} odcinków",
|
"LabelDownloadNEpisodes": "Ściąganie {0} odcinków",
|
||||||
"LabelDuration": "Czas trwania",
|
"LabelDuration": "Czas trwania",
|
||||||
|
"LabelDurationComparisonExactMatch": "(dokładne dopasowanie)",
|
||||||
"LabelDurationComparisonLonger": "({0} dłużej)",
|
"LabelDurationComparisonLonger": "({0} dłużej)",
|
||||||
"LabelDurationComparisonShorter": "({0} krócej)",
|
"LabelDurationComparisonShorter": "({0} krócej)",
|
||||||
"LabelDurationFound": "Znaleziona długość:",
|
"LabelDurationFound": "Znaleziona długość:",
|
||||||
|
"LabelEbook": "Ebook",
|
||||||
"LabelEbooks": "Ebooki",
|
"LabelEbooks": "Ebooki",
|
||||||
"LabelEdit": "Edytuj",
|
"LabelEdit": "Edytuj",
|
||||||
|
"LabelEmail": "E-mail",
|
||||||
"LabelEmailSettingsFromAddress": "Z adresu",
|
"LabelEmailSettingsFromAddress": "Z adresu",
|
||||||
"LabelEmailSettingsRejectUnauthorized": "Odrzuć nieautoryzowane certyfikaty",
|
"LabelEmailSettingsRejectUnauthorized": "Odrzuć nieautoryzowane certyfikaty",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Wyłączenie walidacji certyfikatów SSL może narazić cię na ryzyka bezpieczeństwa, takie jak ataki man-in-the-middle. Wyłącz tą opcję wyłącznie jeśli rozumiesz tego skutki i ufasz serwerowi pocztowemu, do którego się podłączasz.",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Wyłączenie walidacji certyfikatów SSL może narazić cię na ryzyka bezpieczeństwa, takie jak ataki man-in-the-middle. Wyłącz tą opcję wyłącznie jeśli rozumiesz tego skutki i ufasz serwerowi pocztowemu, do którego się podłączasz.",
|
||||||
"LabelEmailSettingsSecure": "Bezpieczeństwo",
|
"LabelEmailSettingsSecure": "Bezpieczeństwo",
|
||||||
"LabelEmailSettingsSecureHelp": "Jeśli włączysz, połączenie będzie korzystać z TLS podczas łączenia do serwera. Jeśli wyłączysz, TLS będzie wykorzystane jeśli serwer wspiera rozszerzenie STARTTLS. W większości przypadków włącz to ustawienie jeśli łączysz się do portu 465. Dla portów 587 lub 25 pozostaw to ustawienie wyłączone. (na podstawie nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Jeśli włączysz, połączenie będzie korzystać z TLS podczas łączenia do serwera. Jeśli wyłączysz, TLS będzie wykorzystane jeśli serwer wspiera rozszerzenie STARTTLS. W większości przypadków włącz to ustawienie jeśli łączysz się do portu 465. Dla portów 587 lub 25 pozostaw to ustawienie wyłączone. (na podstawie nodemailer.com/smtp/#authentication)",
|
||||||
|
"LabelEmailSettingsTestAddress": "Adres testowy",
|
||||||
"LabelEmbeddedCover": "Wbudowana okładka",
|
"LabelEmbeddedCover": "Wbudowana okładka",
|
||||||
"LabelEnable": "Włącz",
|
"LabelEnable": "Włącz",
|
||||||
"LabelEnd": "Zakończ",
|
"LabelEnd": "Zakończ",
|
||||||
@@ -278,16 +301,21 @@
|
|||||||
"LabelEpisode": "Odcinek",
|
"LabelEpisode": "Odcinek",
|
||||||
"LabelEpisodeTitle": "Tytuł odcinka",
|
"LabelEpisodeTitle": "Tytuł odcinka",
|
||||||
"LabelEpisodeType": "Typ odcinka",
|
"LabelEpisodeType": "Typ odcinka",
|
||||||
|
"LabelEpisodes": "Epizody",
|
||||||
"LabelExample": "Przykład",
|
"LabelExample": "Przykład",
|
||||||
"LabelExpandSeries": "Rozwiń serie",
|
"LabelExpandSeries": "Rozwiń serie",
|
||||||
"LabelExpandSubSeries": "Rozwiń podserie",
|
"LabelExpandSubSeries": "Rozwiń podserie",
|
||||||
"LabelExplicit": "Nieprzyzwoite",
|
"LabelExplicit": "Nieprzyzwoite",
|
||||||
|
"LabelExplicitChecked": "Nieprzyzwoite (sprawdzone)",
|
||||||
|
"LabelExplicitUnchecked": "Przyzwoite (niesprawdzone)",
|
||||||
"LabelExportOPML": "Wyeksportuj OPML",
|
"LabelExportOPML": "Wyeksportuj OPML",
|
||||||
"LabelFeedURL": "URL kanału",
|
"LabelFeedURL": "URL kanału",
|
||||||
"LabelFetchingMetadata": "Pobieranie metadanych",
|
"LabelFetchingMetadata": "Pobieranie metadanych",
|
||||||
"LabelFile": "Plik",
|
"LabelFile": "Plik",
|
||||||
"LabelFileBirthtime": "Data utworzenia pliku",
|
"LabelFileBirthtime": "Data utworzenia pliku",
|
||||||
|
"LabelFileBornDate": "Utworzony {0}",
|
||||||
"LabelFileModified": "Data modyfikacji pliku",
|
"LabelFileModified": "Data modyfikacji pliku",
|
||||||
|
"LabelFileModifiedDate": "Modyfikowany {0}",
|
||||||
"LabelFilename": "Nazwa pliku",
|
"LabelFilename": "Nazwa pliku",
|
||||||
"LabelFilterByUser": "Filtruj według danego użytkownika",
|
"LabelFilterByUser": "Filtruj według danego użytkownika",
|
||||||
"LabelFindEpisodes": "Znajdź odcinki",
|
"LabelFindEpisodes": "Znajdź odcinki",
|
||||||
@@ -297,8 +325,10 @@
|
|||||||
"LabelFontBold": "Pogrubiony",
|
"LabelFontBold": "Pogrubiony",
|
||||||
"LabelFontBoldness": "Grubość czcionki",
|
"LabelFontBoldness": "Grubość czcionki",
|
||||||
"LabelFontFamily": "Rodzina czcionek",
|
"LabelFontFamily": "Rodzina czcionek",
|
||||||
|
"LabelFontItalic": "Kursywa",
|
||||||
"LabelFontScale": "Rozmiar czcionki",
|
"LabelFontScale": "Rozmiar czcionki",
|
||||||
"LabelFontStrikethrough": "Przekreślony",
|
"LabelFontStrikethrough": "Przekreślony",
|
||||||
|
"LabelFormat": "Format",
|
||||||
"LabelGenre": "Gatunek",
|
"LabelGenre": "Gatunek",
|
||||||
"LabelGenres": "Gatunki",
|
"LabelGenres": "Gatunki",
|
||||||
"LabelHardDeleteFile": "Usuń trwale plik",
|
"LabelHardDeleteFile": "Usuń trwale plik",
|
||||||
@@ -306,6 +336,7 @@
|
|||||||
"LabelHasSupplementaryEbook": "Posiada dodatkowy ebook",
|
"LabelHasSupplementaryEbook": "Posiada dodatkowy ebook",
|
||||||
"LabelHideSubtitles": "Ukryj napisy",
|
"LabelHideSubtitles": "Ukryj napisy",
|
||||||
"LabelHighestPriority": "Najwyższy priorytet",
|
"LabelHighestPriority": "Najwyższy priorytet",
|
||||||
|
"LabelHost": "Host",
|
||||||
"LabelHour": "Godzina",
|
"LabelHour": "Godzina",
|
||||||
"LabelHours": "Godziny",
|
"LabelHours": "Godziny",
|
||||||
"LabelIcon": "Ikona",
|
"LabelIcon": "Ikona",
|
||||||
@@ -324,6 +355,7 @@
|
|||||||
"LabelIntervalEveryHour": "Każdej godziny",
|
"LabelIntervalEveryHour": "Każdej godziny",
|
||||||
"LabelInvert": "Inversja",
|
"LabelInvert": "Inversja",
|
||||||
"LabelItem": "Pozycja",
|
"LabelItem": "Pozycja",
|
||||||
|
"LabelJumpBackwardAmount": "Rozmiar skoku do przodu",
|
||||||
"LabelLanguage": "Język",
|
"LabelLanguage": "Język",
|
||||||
"LabelLanguageDefaultServer": "Domyślny język serwera",
|
"LabelLanguageDefaultServer": "Domyślny język serwera",
|
||||||
"LabelLanguages": "Języki",
|
"LabelLanguages": "Języki",
|
||||||
@@ -338,10 +370,13 @@
|
|||||||
"LabelLess": "Mniej",
|
"LabelLess": "Mniej",
|
||||||
"LabelLibrariesAccessibleToUser": "Biblioteki dostępne dla użytkownika",
|
"LabelLibrariesAccessibleToUser": "Biblioteki dostępne dla użytkownika",
|
||||||
"LabelLibrary": "Biblioteka",
|
"LabelLibrary": "Biblioteka",
|
||||||
|
"LabelLibraryFilterSublistEmpty": "Brak {0}",
|
||||||
"LabelLibraryItem": "Element biblioteki",
|
"LabelLibraryItem": "Element biblioteki",
|
||||||
"LabelLibraryName": "Nazwa biblioteki",
|
"LabelLibraryName": "Nazwa biblioteki",
|
||||||
|
"LabelLimit": "Limit",
|
||||||
"LabelLineSpacing": "Odstęp między wierszami",
|
"LabelLineSpacing": "Odstęp między wierszami",
|
||||||
"LabelListenAgain": "Słuchaj ponownie",
|
"LabelListenAgain": "Słuchaj ponownie",
|
||||||
|
"LabelLogLevelDebug": "Debugowanie",
|
||||||
"LabelLogLevelInfo": "Informacja",
|
"LabelLogLevelInfo": "Informacja",
|
||||||
"LabelLogLevelWarn": "Ostrzeżenie",
|
"LabelLogLevelWarn": "Ostrzeżenie",
|
||||||
"LabelLookForNewEpisodesAfterDate": "Szukaj nowych odcinków po dacie",
|
"LabelLookForNewEpisodesAfterDate": "Szukaj nowych odcinków po dacie",
|
||||||
@@ -351,6 +386,7 @@
|
|||||||
"LabelMediaPlayer": "Odtwarzacz",
|
"LabelMediaPlayer": "Odtwarzacz",
|
||||||
"LabelMediaType": "Typ mediów",
|
"LabelMediaType": "Typ mediów",
|
||||||
"LabelMetaTag": "Tag",
|
"LabelMetaTag": "Tag",
|
||||||
|
"LabelMetaTags": "Meta Tagi",
|
||||||
"LabelMetadataOrderOfPrecedenceDescription": "Źródła metadanych o wyższym priorytecie będą zastępują źródła o niższym priorytecie",
|
"LabelMetadataOrderOfPrecedenceDescription": "Źródła metadanych o wyższym priorytecie będą zastępują źródła o niższym priorytecie",
|
||||||
"LabelMetadataProvider": "Dostawca metadanych",
|
"LabelMetadataProvider": "Dostawca metadanych",
|
||||||
"LabelMinute": "Minuta",
|
"LabelMinute": "Minuta",
|
||||||
@@ -358,6 +394,7 @@
|
|||||||
"LabelMissing": "Brakujący",
|
"LabelMissing": "Brakujący",
|
||||||
"LabelMissingEbook": "Nie posiada ebooka",
|
"LabelMissingEbook": "Nie posiada ebooka",
|
||||||
"LabelMissingSupplementaryEbook": "Nie posiada dodatkowego ebooka",
|
"LabelMissingSupplementaryEbook": "Nie posiada dodatkowego ebooka",
|
||||||
|
"LabelMobileRedirectURIs": "Dozwolone URI przekierowań mobilnych",
|
||||||
"LabelMore": "Więcej",
|
"LabelMore": "Więcej",
|
||||||
"LabelMoreInfo": "Więcej informacji",
|
"LabelMoreInfo": "Więcej informacji",
|
||||||
"LabelName": "Nazwa",
|
"LabelName": "Nazwa",
|
||||||
|
|||||||
@@ -98,7 +98,6 @@
|
|||||||
"ButtonStats": "Статистика",
|
"ButtonStats": "Статистика",
|
||||||
"ButtonSubmit": "Применить",
|
"ButtonSubmit": "Применить",
|
||||||
"ButtonTest": "Тест",
|
"ButtonTest": "Тест",
|
||||||
"ButtonUnlinkOpedId": "Отвязать OpenID",
|
|
||||||
"ButtonUpload": "Загрузить",
|
"ButtonUpload": "Загрузить",
|
||||||
"ButtonUploadBackup": "Загрузить бэкап",
|
"ButtonUploadBackup": "Загрузить бэкап",
|
||||||
"ButtonUploadCover": "Загрузить обложку",
|
"ButtonUploadCover": "Загрузить обложку",
|
||||||
|
|||||||
+782
-15
@@ -5,7 +5,7 @@
|
|||||||
"ButtonAddLibrary": "Dodaj knjižnico",
|
"ButtonAddLibrary": "Dodaj knjižnico",
|
||||||
"ButtonAddPodcasts": "Dodaj podcast",
|
"ButtonAddPodcasts": "Dodaj podcast",
|
||||||
"ButtonAddUser": "Dodaj uporabnika",
|
"ButtonAddUser": "Dodaj uporabnika",
|
||||||
"ButtonAddYourFirstLibrary": "Dodaj tvojo prvo knjižnico",
|
"ButtonAddYourFirstLibrary": "Dodajte svojo prvo knjižnico",
|
||||||
"ButtonApply": "Uveljavi",
|
"ButtonApply": "Uveljavi",
|
||||||
"ButtonApplyChapters": "Uveljavi poglavja",
|
"ButtonApplyChapters": "Uveljavi poglavja",
|
||||||
"ButtonAuthors": "Avtorji",
|
"ButtonAuthors": "Avtorji",
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
"ButtonCancelEncode": "Prekliči prekodiranje",
|
"ButtonCancelEncode": "Prekliči prekodiranje",
|
||||||
"ButtonChangeRootPassword": "Zamenjaj korensko geslo",
|
"ButtonChangeRootPassword": "Zamenjaj korensko geslo",
|
||||||
"ButtonCheckAndDownloadNewEpisodes": "Preveri in prenesi nove epizode",
|
"ButtonCheckAndDownloadNewEpisodes": "Preveri in prenesi nove epizode",
|
||||||
"ButtonChooseAFolder": "Izberi mapo",
|
"ButtonChooseAFolder": "Izberite mapo",
|
||||||
"ButtonChooseFiles": "Izberi datoteke",
|
"ButtonChooseFiles": "Izberite datoteke",
|
||||||
"ButtonClearFilter": "Počisti filter",
|
"ButtonClearFilter": "Počisti filter",
|
||||||
"ButtonCloseFeed": "Zapri vir",
|
"ButtonCloseFeed": "Zapri vir",
|
||||||
"ButtonCloseSession": "Zapri odprto sejo",
|
"ButtonCloseSession": "Zapri odprto sejo",
|
||||||
"ButtonCollections": "Zbirke",
|
"ButtonCollections": "Zbirke",
|
||||||
"ButtonConfigureScanner": "Nastavi skener",
|
"ButtonConfigureScanner": "Nastavi pregledovalnik",
|
||||||
"ButtonCreate": "Ustvari",
|
"ButtonCreate": "Ustvari",
|
||||||
"ButtonCreateBackup": "Ustvari varnostno kopijo",
|
"ButtonCreateBackup": "Ustvari varnostno kopijo",
|
||||||
"ButtonDelete": "Izbriši",
|
"ButtonDelete": "Izbriši",
|
||||||
@@ -30,9 +30,9 @@
|
|||||||
"ButtonEditChapters": "Uredi poglavja",
|
"ButtonEditChapters": "Uredi poglavja",
|
||||||
"ButtonEditPodcast": "Uredi podcast",
|
"ButtonEditPodcast": "Uredi podcast",
|
||||||
"ButtonEnable": "Omogoči",
|
"ButtonEnable": "Omogoči",
|
||||||
"ButtonFireAndFail": "Zaženi in je neuspešno",
|
"ButtonFireAndFail": "Zaženi in je bilo neuspešno",
|
||||||
"ButtonFireOnTest": "Zaženi samo na dogodku onTest",
|
"ButtonFireOnTest": "Zaženi samo na dogodku onTest",
|
||||||
"ButtonForceReScan": "Prisilno ponovno skeniranje",
|
"ButtonForceReScan": "Prisilno ponovno pregledovanje",
|
||||||
"ButtonFullPath": "Polna pot",
|
"ButtonFullPath": "Polna pot",
|
||||||
"ButtonHide": "Skrij",
|
"ButtonHide": "Skrij",
|
||||||
"ButtonHome": "Domov",
|
"ButtonHome": "Domov",
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
"ButtonQueueRemoveItem": "Odstrani iz čakalne vrste",
|
"ButtonQueueRemoveItem": "Odstrani iz čakalne vrste",
|
||||||
"ButtonQuickEmbedMetadata": "Hitra vdelava metapodatkov",
|
"ButtonQuickEmbedMetadata": "Hitra vdelava metapodatkov",
|
||||||
"ButtonQuickMatch": "Hitro ujemanje",
|
"ButtonQuickMatch": "Hitro ujemanje",
|
||||||
"ButtonReScan": "Ponovno iskanje",
|
"ButtonReScan": "Ponovno pregledovanje",
|
||||||
"ButtonRead": "Preberi",
|
"ButtonRead": "Preberi",
|
||||||
"ButtonReadLess": "Preberi manj",
|
"ButtonReadLess": "Preberi manj",
|
||||||
"ButtonReadMore": "Preberi več",
|
"ButtonReadMore": "Preberi več",
|
||||||
@@ -84,10 +84,10 @@
|
|||||||
"ButtonSave": "Shrani",
|
"ButtonSave": "Shrani",
|
||||||
"ButtonSaveAndClose": "Shrani iz zapri",
|
"ButtonSaveAndClose": "Shrani iz zapri",
|
||||||
"ButtonSaveTracklist": "Shrani seznam skladb",
|
"ButtonSaveTracklist": "Shrani seznam skladb",
|
||||||
"ButtonScan": "Skeniranje",
|
"ButtonScan": "Pregledovanje",
|
||||||
"ButtonScanLibrary": "Skeniraj knjižnico",
|
"ButtonScanLibrary": "Preglej knjižnico",
|
||||||
"ButtonSearch": "Poišči",
|
"ButtonSearch": "Poišči",
|
||||||
"ButtonSelectFolderPath": "Izberi pot mape",
|
"ButtonSelectFolderPath": "Izberite pot do mape",
|
||||||
"ButtonSeries": "Serije",
|
"ButtonSeries": "Serije",
|
||||||
"ButtonSetChaptersFromTracks": "Nastavi poglavja za posnetke",
|
"ButtonSetChaptersFromTracks": "Nastavi poglavja za posnetke",
|
||||||
"ButtonShare": "Deli",
|
"ButtonShare": "Deli",
|
||||||
@@ -98,7 +98,6 @@
|
|||||||
"ButtonStats": "Statistika",
|
"ButtonStats": "Statistika",
|
||||||
"ButtonSubmit": "Posreduj",
|
"ButtonSubmit": "Posreduj",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpedId": "Prekini povezavo OpenID",
|
|
||||||
"ButtonUpload": "Naloži",
|
"ButtonUpload": "Naloži",
|
||||||
"ButtonUploadBackup": "Naloži varnostno kopijo",
|
"ButtonUploadBackup": "Naloži varnostno kopijo",
|
||||||
"ButtonUploadCover": "Naloži naslovnico",
|
"ButtonUploadCover": "Naloži naslovnico",
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
"HeaderBackups": "Varnostne kopije",
|
"HeaderBackups": "Varnostne kopije",
|
||||||
"HeaderChangePassword": "Zamenjaj geslo",
|
"HeaderChangePassword": "Zamenjaj geslo",
|
||||||
"HeaderChapters": "Poglavja",
|
"HeaderChapters": "Poglavja",
|
||||||
"HeaderChooseAFolder": "Izberi mapo",
|
"HeaderChooseAFolder": "Izberite mapo",
|
||||||
"HeaderCollection": "Zbirka",
|
"HeaderCollection": "Zbirka",
|
||||||
"HeaderCollectionItems": "Elementi zbirke",
|
"HeaderCollectionItems": "Elementi zbirke",
|
||||||
"HeaderCover": "Naslovnica",
|
"HeaderCover": "Naslovnica",
|
||||||
@@ -178,7 +177,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Odstrani {0} epizod",
|
"HeaderRemoveEpisodes": "Odstrani {0} epizod",
|
||||||
"HeaderSavedMediaProgress": "Shranjen napredek predstavnosti",
|
"HeaderSavedMediaProgress": "Shranjen napredek predstavnosti",
|
||||||
"HeaderSchedule": "Načrtovanje",
|
"HeaderSchedule": "Načrtovanje",
|
||||||
"HeaderScheduleLibraryScans": "Načrtuj samodejno skeniranje knjižnice",
|
"HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice",
|
||||||
"HeaderSession": "Seja",
|
"HeaderSession": "Seja",
|
||||||
"HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja",
|
"HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja",
|
||||||
"HeaderSettings": "Nastavitve",
|
"HeaderSettings": "Nastavitve",
|
||||||
@@ -189,7 +188,7 @@
|
|||||||
"HeaderSleepTimer": "Časovnik za izklop",
|
"HeaderSleepTimer": "Časovnik za izklop",
|
||||||
"HeaderStatsLargestItems": "Največji elementi",
|
"HeaderStatsLargestItems": "Največji elementi",
|
||||||
"HeaderStatsLongestItems": "Najdaljši elementi (ure)",
|
"HeaderStatsLongestItems": "Najdaljši elementi (ure)",
|
||||||
"HeaderStatsMinutesListeningChart": "Minute poslušanja (zadnjih 7 dni)",
|
"HeaderStatsMinutesListeningChart": "Minut poslušanja (zadnjih 7 dni)",
|
||||||
"HeaderStatsRecentSessions": "Nedavne seje",
|
"HeaderStatsRecentSessions": "Nedavne seje",
|
||||||
"HeaderStatsTop10Authors": "Najboljših 10 avtorjev",
|
"HeaderStatsTop10Authors": "Najboljših 10 avtorjev",
|
||||||
"HeaderStatsTop5Genres": "Najboljših 5 žanrov",
|
"HeaderStatsTop5Genres": "Najboljših 5 žanrov",
|
||||||
@@ -204,5 +203,773 @@
|
|||||||
"HeaderYourStats": "Tvoja statistika",
|
"HeaderYourStats": "Tvoja statistika",
|
||||||
"LabelAbridged": "Skrajšano",
|
"LabelAbridged": "Skrajšano",
|
||||||
"LabelAbridgedChecked": "Skrajšano (omogočeno)",
|
"LabelAbridgedChecked": "Skrajšano (omogočeno)",
|
||||||
"LabelAbridgedUnchecked": "Neskrajšano (onemogočeno)"
|
"LabelAbridgedUnchecked": "Neskrajšano (onemogočeno)",
|
||||||
|
"LabelAccessibleBy": "Dostopno iz",
|
||||||
|
"LabelAccountType": "Vrsta računa",
|
||||||
|
"LabelAccountTypeAdmin": "Administrator",
|
||||||
|
"LabelAccountTypeGuest": "Gost",
|
||||||
|
"LabelAccountTypeUser": "Uporabnik",
|
||||||
|
"LabelActivity": "Aktivnost",
|
||||||
|
"LabelAddToCollection": "Dodaj v zbirko",
|
||||||
|
"LabelAddToCollectionBatch": "Dodaj {0} knjig v zbirko",
|
||||||
|
"LabelAddToPlaylist": "Dodaj na seznam predvajanja",
|
||||||
|
"LabelAddToPlaylistBatch": "Dodaj {0} elementov v seznam predvajanja",
|
||||||
|
"LabelAddedAt": "Dodano ob",
|
||||||
|
"LabelAddedDate": "Dodano {0}",
|
||||||
|
"LabelAdminUsersOnly": "Samo administratorji",
|
||||||
|
"LabelAll": "Vsi",
|
||||||
|
"LabelAllUsers": "Vsi uporabniki",
|
||||||
|
"LabelAllUsersExcludingGuests": "Vsi uporabniki razen gosti",
|
||||||
|
"LabelAllUsersIncludingGuests": "Vsi uporabniki vključno z gosti",
|
||||||
|
"LabelAlreadyInYourLibrary": "Že v tvoji knjižnici",
|
||||||
|
"LabelAppend": "Priloži",
|
||||||
|
"LabelAuthor": "Avtor",
|
||||||
|
"LabelAuthorFirstLast": "Avtor (ime priimek)",
|
||||||
|
"LabelAuthorLastFirst": "Avtor (priimek, ime)",
|
||||||
|
"LabelAuthors": "Avtorji",
|
||||||
|
"LabelAutoDownloadEpisodes": "Samodejni prenos epizod",
|
||||||
|
"LabelAutoFetchMetadata": "Samodejno pridobivanje metapodatkov",
|
||||||
|
"LabelAutoFetchMetadataHelp": "Pridobi metapodatke za naslov, avtorja in serijo za poenostavitev nalaganja. Po nalaganju bo morda treba ujemanje dodatnih metapodatkov.",
|
||||||
|
"LabelAutoLaunch": "Samodejni zagon",
|
||||||
|
"LabelAutoLaunchDescription": "Samodejna preusmeritev na ponudnika avtentikacije ob navigaciji na prijavno stran (ročna preglasitev poti <code>/login?autoLaunch=0</code>)",
|
||||||
|
"LabelAutoRegister": "Samodejna registracija",
|
||||||
|
"LabelAutoRegisterDescription": "Po prijavi samodejno ustvari nove uporabnike",
|
||||||
|
"LabelBackToUser": "Nazaj na uporabnika",
|
||||||
|
"LabelBackupLocation": "Lokacija rezervne kopije",
|
||||||
|
"LabelBackupsEnableAutomaticBackups": "Omogoči samodejno varnostno kopiranje",
|
||||||
|
"LabelBackupsEnableAutomaticBackupsHelp": "Varnostne kopije shranjene v /metadata/backups",
|
||||||
|
"LabelBackupsMaxBackupSize": "Največja velikost varnostne kopije (v GB) (0 za neomejeno)",
|
||||||
|
"LabelBackupsMaxBackupSizeHelp": "Kot zaščita pred napačno konfiguracijo, varnostne kopije ne bodo uspele, če presežejo konfigurirano velikost.",
|
||||||
|
"LabelBackupsNumberToKeep": "Število varnostnih kopij, ki jih je treba hraniti",
|
||||||
|
"LabelBackupsNumberToKeepHelp": "Naenkrat bo odstranjena samo ena varnostna kopija, če že imate več varnostnih kopij, jih odstranite ročno.",
|
||||||
|
"LabelBitrate": "Bitna hitrost",
|
||||||
|
"LabelBooks": "Knjige",
|
||||||
|
"LabelButtonText": "Besedilo gumba",
|
||||||
|
"LabelByAuthor": "od {0}",
|
||||||
|
"LabelChangePassword": "Spremeni geslo",
|
||||||
|
"LabelChannels": "Kanali",
|
||||||
|
"LabelChapterTitle": "Naslov poglavja",
|
||||||
|
"LabelChapters": "Poglavja",
|
||||||
|
"LabelChaptersFound": "najdenih poglavij",
|
||||||
|
"LabelClickForMoreInfo": "Klikni za več informacij",
|
||||||
|
"LabelClosePlayer": "Zapri predvajalnik",
|
||||||
|
"LabelCodec": "Kodek",
|
||||||
|
"LabelCollapseSeries": "Strni serije",
|
||||||
|
"LabelCollapseSubSeries": "Strni podserije",
|
||||||
|
"LabelCollection": "Zbirka",
|
||||||
|
"LabelCollections": "Zbirke",
|
||||||
|
"LabelComplete": "Končano",
|
||||||
|
"LabelConfirmPassword": "Potrdi geslo",
|
||||||
|
"LabelContinueListening": "Nadaljuj poslušanje",
|
||||||
|
"LabelContinueReading": "Nadaljuj branje",
|
||||||
|
"LabelContinueSeries": "Nadaljuj s serijo",
|
||||||
|
"LabelCover": "Naslovnica",
|
||||||
|
"LabelCoverImageURL": "URL naslovne slike",
|
||||||
|
"LabelCreatedAt": "Ustvarjeno ob",
|
||||||
|
"LabelCronExpression": "Cron izraz",
|
||||||
|
"LabelCurrent": "Trenutno",
|
||||||
|
"LabelCurrently": "Trenutno:",
|
||||||
|
"LabelCustomCronExpression": "Cron izraz po meri:",
|
||||||
|
"LabelDatetime": "Datum in ura",
|
||||||
|
"LabelDays": "Dnevi",
|
||||||
|
"LabelDeleteFromFileSystemCheckbox": "Izbriši iz datotečnega sistema (počisti polje, če želiš odstraniti samo iz zbirke podatkov)",
|
||||||
|
"LabelDescription": "Opis",
|
||||||
|
"LabelDeselectAll": "Odznači vse",
|
||||||
|
"LabelDevice": "Naprava",
|
||||||
|
"LabelDeviceInfo": "Podatki o napravi",
|
||||||
|
"LabelDeviceIsAvailableTo": "Naprava je na voljo za...",
|
||||||
|
"LabelDirectory": "Imenik",
|
||||||
|
"LabelDiscFromFilename": "Disk iz imena datoteke",
|
||||||
|
"LabelDiscFromMetadata": "Disk iz metapodatkov",
|
||||||
|
"LabelDiscover": "Odkrij",
|
||||||
|
"LabelDownload": "Prenos",
|
||||||
|
"LabelDownloadNEpisodes": "Prenesi {0} epizod",
|
||||||
|
"LabelDuration": "Trajanje",
|
||||||
|
"LabelDurationComparisonExactMatch": "(natančno ujemanje)",
|
||||||
|
"LabelDurationComparisonLonger": "({0} dlje)",
|
||||||
|
"LabelDurationComparisonShorter": "({0} krajše)",
|
||||||
|
"LabelDurationFound": "Najdeno trajanje:",
|
||||||
|
"LabelEbook": "Eknjiga",
|
||||||
|
"LabelEbooks": "Eknjige",
|
||||||
|
"LabelEdit": "Uredi",
|
||||||
|
"LabelEmail": "E-pošta",
|
||||||
|
"LabelEmailSettingsFromAddress": "Iz naslova",
|
||||||
|
"LabelEmailSettingsRejectUnauthorized": "Zavrni nepooblaščena potrdila",
|
||||||
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Če onemogočite preverjanje veljavnosti potrdila SSL, lahko izpostavite svojo povezavo varnostnim tveganjem, kot so napadi človek v sredini. To možnost onemogočite le, če razumete posledice in zaupate poštnemu strežniku, s katerim se povezujete.",
|
||||||
|
"LabelEmailSettingsSecure": "Varno",
|
||||||
|
"LabelEmailSettingsSecureHelp": "Če je omogočeno, bo povezava pri povezovanju s strežnikom uporabljala TLS. Če je onemogočeno, se TLS uporablja, če strežnik podpira razširitev STARTTLS. V večini primerov nastavite to vrednost na omogočeno, če se povezujete z vrati 465. Za vrata 587 ali 25 naj ostane onemogočeno. (iz nodemailer.com/smtp/#authentication)",
|
||||||
|
"LabelEmailSettingsTestAddress": "Testiraj naslov",
|
||||||
|
"LabelEmbeddedCover": "Vdelana naslovnica",
|
||||||
|
"LabelEnable": "Omogoči",
|
||||||
|
"LabelEnd": "Konec",
|
||||||
|
"LabelEndOfChapter": "Konec poglavja",
|
||||||
|
"LabelEpisode": "Epizoda",
|
||||||
|
"LabelEpisodeTitle": "Naslov epizode",
|
||||||
|
"LabelEpisodeType": "Tip epizode",
|
||||||
|
"LabelEpisodes": "Epizode",
|
||||||
|
"LabelExample": "Primer",
|
||||||
|
"LabelExpandSeries": "Razširi serije",
|
||||||
|
"LabelExpandSubSeries": "Razširi podserije",
|
||||||
|
"LabelExplicit": "Eksplicitno",
|
||||||
|
"LabelExplicitChecked": "Eksplicitno (omogočeno)",
|
||||||
|
"LabelExplicitUnchecked": "Ne eksplicitno (onemogočeno)",
|
||||||
|
"LabelExportOPML": "Izvozi OPML",
|
||||||
|
"LabelFeedURL": "URL vir",
|
||||||
|
"LabelFetchingMetadata": "Pridobivam metapodatke",
|
||||||
|
"LabelFile": "Datoteka",
|
||||||
|
"LabelFileBirthtime": "Čas ustvarjanja datoteke",
|
||||||
|
"LabelFileBornDate": "Ustvarjena {0}",
|
||||||
|
"LabelFileModified": "Datoteke spremenjena",
|
||||||
|
"LabelFileModifiedDate": "Spremenjena {0}",
|
||||||
|
"LabelFilename": "Ime datoteke",
|
||||||
|
"LabelFilterByUser": "Filtriraj po uporabniku",
|
||||||
|
"LabelFindEpisodes": "Poišči epizode",
|
||||||
|
"LabelFinished": "Zaključeno",
|
||||||
|
"LabelFolder": "Mapa",
|
||||||
|
"LabelFolders": "Mape",
|
||||||
|
"LabelFontBold": "Krepko",
|
||||||
|
"LabelFontBoldness": "Krepkost pisave",
|
||||||
|
"LabelFontFamily": "Družina pisave",
|
||||||
|
"LabelFontItalic": "Ležeče",
|
||||||
|
"LabelFontScale": "Merilo pisave",
|
||||||
|
"LabelFontStrikethrough": "Prečrtano",
|
||||||
|
"LabelFormat": "Oblika",
|
||||||
|
"LabelGenre": "Žanr",
|
||||||
|
"LabelGenres": "Žanri",
|
||||||
|
"LabelHardDeleteFile": "Trdo brisanje datoteke",
|
||||||
|
"LabelHasEbook": "Ima eknjigo",
|
||||||
|
"LabelHasSupplementaryEbook": "Ima dodatno eknjigo",
|
||||||
|
"LabelHideSubtitles": "Skrij podnapise",
|
||||||
|
"LabelHighestPriority": "Najvišja prioriteta",
|
||||||
|
"LabelHost": "Gostitelj",
|
||||||
|
"LabelHour": "Ura",
|
||||||
|
"LabelHours": "Ure",
|
||||||
|
"LabelIcon": "Ikona",
|
||||||
|
"LabelImageURLFromTheWeb": "URL slike iz spleta",
|
||||||
|
"LabelInProgress": "V teku",
|
||||||
|
"LabelIncludeInTracklist": "Vključi v seznam skladb",
|
||||||
|
"LabelIncomplete": "Nepopolno",
|
||||||
|
"LabelInterval": "Interval",
|
||||||
|
"LabelIntervalCustomDailyWeekly": "Dnevno/tedensko po meri",
|
||||||
|
"LabelIntervalEvery12Hours": "Vsakih 12 ur",
|
||||||
|
"LabelIntervalEvery15Minutes": "Vsakih 15 minut",
|
||||||
|
"LabelIntervalEvery2Hours": "Vsake 2 uri",
|
||||||
|
"LabelIntervalEvery30Minutes": "Vsakih 30 minut",
|
||||||
|
"LabelIntervalEvery6Hours": "Vsakih 6 ur",
|
||||||
|
"LabelIntervalEveryDay": "Vsak dan",
|
||||||
|
"LabelIntervalEveryHour": "Vsako uro",
|
||||||
|
"LabelInvert": "Obrni izbor",
|
||||||
|
"LabelItem": "Element",
|
||||||
|
"LabelJumpBackwardAmount": "Količina skoka nazaj",
|
||||||
|
"LabelJumpForwardAmount": "Količina skoka naprej",
|
||||||
|
"LabelLanguage": "Jezik",
|
||||||
|
"LabelLanguageDefaultServer": "Privzeti jezik strežnika",
|
||||||
|
"LabelLanguages": "Jeziki",
|
||||||
|
"LabelLastBookAdded": "Zadnja dodana knjiga",
|
||||||
|
"LabelLastBookUpdated": "Zadnja posodobljena knjiga",
|
||||||
|
"LabelLastSeen": "Nazadnje viden",
|
||||||
|
"LabelLastTime": "Zadnji čas",
|
||||||
|
"LabelLastUpdate": "Zadnja posodobitev",
|
||||||
|
"LabelLayout": "Postavitev",
|
||||||
|
"LabelLayoutSinglePage": "Ena stran",
|
||||||
|
"LabelLayoutSplitPage": "Razdeli stran",
|
||||||
|
"LabelLess": "Manj",
|
||||||
|
"LabelLibrariesAccessibleToUser": "Knjižnice, dostopne uporabniku",
|
||||||
|
"LabelLibrary": "Knjižnica",
|
||||||
|
"LabelLibraryFilterSublistEmpty": "Ne {0}",
|
||||||
|
"LabelLibraryItem": "Element knjižnice",
|
||||||
|
"LabelLibraryName": "Ime knjižnice",
|
||||||
|
"LabelLimit": "Omejitev",
|
||||||
|
"LabelLineSpacing": "Razmik med vrsticami",
|
||||||
|
"LabelListenAgain": "Poslušaj znova",
|
||||||
|
"LabelLogLevelDebug": "Odpravljanje napak",
|
||||||
|
"LabelLogLevelInfo": "Info",
|
||||||
|
"LabelLogLevelWarn": "Opozoritve",
|
||||||
|
"LabelLookForNewEpisodesAfterDate": "Poiščite nove epizode po tem datumu",
|
||||||
|
"LabelLowestPriority": "Najnižja prioriteta",
|
||||||
|
"LabelMatchExistingUsersBy": "Poveži obstoječe uporabnike po",
|
||||||
|
"LabelMatchExistingUsersByDescription": "Uporablja se za povezovanje obstoječih uporabnikov. Ko se vzpostavi povezava, se bodo uporabniki ujemali z enoličnim ID-jem vašega ponudnika SSO",
|
||||||
|
"LabelMediaPlayer": "Medijski predvajalnik",
|
||||||
|
"LabelMediaType": "Vrsta medija",
|
||||||
|
"LabelMetaTag": "Meta oznaka",
|
||||||
|
"LabelMetaTags": "Meta oznake",
|
||||||
|
"LabelMetadataOrderOfPrecedenceDescription": "Viri metapodatkov višje prioritete bodo preglasili vire metapodatkov nižje prioritete",
|
||||||
|
"LabelMetadataProvider": "Ponudnik metapodatkov",
|
||||||
|
"LabelMinute": "Minuta",
|
||||||
|
"LabelMinutes": "Minute",
|
||||||
|
"LabelMissing": "Manjkajoče",
|
||||||
|
"LabelMissingEbook": "Nima nobene eknjige",
|
||||||
|
"LabelMissingSupplementaryEbook": "Nima nobene dodatne eknjige",
|
||||||
|
"LabelMobileRedirectURIs": "Dovoljeni mobilni preusmeritveni URI-ji",
|
||||||
|
"LabelMobileRedirectURIsDescription": "To je seznam dovoljenih veljavnih preusmeritvenih URI-jev za mobilne aplikacije. Privzeti je <code>audiobookshelf://oauth</code>, ki ga lahko odstranite ali dopolnite z dodatnimi URI-ji za integracijo aplikacij tretjih oseb. Uporaba zvezdice (<code>*</code>) kot edinega vnosa dovoljuje kateri koli URI.",
|
||||||
|
"LabelMore": "Več",
|
||||||
|
"LabelMoreInfo": "Več informacij",
|
||||||
|
"LabelName": "Naziv",
|
||||||
|
"LabelNarrator": "Bralec",
|
||||||
|
"LabelNarrators": "Bralci",
|
||||||
|
"LabelNew": "Novo",
|
||||||
|
"LabelNewPassword": "Novo geslo",
|
||||||
|
"LabelNewestAuthors": "Najnovejši avtorji",
|
||||||
|
"LabelNewestEpisodes": "Najnovejše epizode",
|
||||||
|
"LabelNextBackupDate": "Naslednji datum varnostnega kopiranja",
|
||||||
|
"LabelNextScheduledRun": "Naslednji načrtovani zagon",
|
||||||
|
"LabelNoCustomMetadataProviders": "Ni ponudnikov metapodatkov po meri",
|
||||||
|
"LabelNoEpisodesSelected": "Izbrana ni nobena epizoda",
|
||||||
|
"LabelNotFinished": "Ni dokončano",
|
||||||
|
"LabelNotStarted": "Ni zagnano",
|
||||||
|
"LabelNotes": "Opombe",
|
||||||
|
"LabelNotificationAppriseURL": "Apprise URL(ji)",
|
||||||
|
"LabelNotificationAvailableVariables": "Razpoložljive spremenljivke",
|
||||||
|
"LabelNotificationBodyTemplate": "Predloga telesa",
|
||||||
|
"LabelNotificationEvent": "Dogodek obvestila",
|
||||||
|
"LabelNotificationTitleTemplate": "Predloga naslova",
|
||||||
|
"LabelNotificationsMaxFailedAttempts": "Najvišje število neuspelih poskusov",
|
||||||
|
"LabelNotificationsMaxFailedAttemptsHelp": "Obvestila so onemogočena, ko se tolikokrat neuspelo pošljejo",
|
||||||
|
"LabelNotificationsMaxQueueSize": "Največja velikost čakalne vrste za dogodke obvestil",
|
||||||
|
"LabelNotificationsMaxQueueSizeHelp": "Dogodki so omejeni na sprožitev 1 na sekundo. Dogodki bodo prezrti, če je čakalna vrsta najvišja. To preprečuje neželeno pošiljanje obvestil.",
|
||||||
|
"LabelNumberOfBooks": "Število knjig",
|
||||||
|
"LabelNumberOfEpisodes": "# od epizod",
|
||||||
|
"LabelOpenIDAdvancedPermsClaimDescription": "Ime zahtevka OpenID, ki vsebuje napredna dovoljenja za uporabniška dejanja v aplikaciji, ki bodo veljala za neskrbniške vloge (<b>če je konfigurirano</b>). Če trditev manjka v odgovoru, bo dostop do ABS zavrnjen. Če ena možnost manjka, bo obravnavana kot <code>false</code>. Zagotovite, da se zahtevek ponudnika identitete ujema s pričakovano strukturo:",
|
||||||
|
"LabelOpenIDClaims": "Pustite naslednje možnosti prazne, da onemogočite napredno dodeljevanje skupin in dovoljenj, nato pa samodejno dodelite skupino 'Uporabnik'.",
|
||||||
|
"LabelOpenIDGroupClaimDescription": "Ime zahtevka OpenID, ki vsebuje seznam uporabnikovih skupin. Običajno imenovane <code>skupine</code>. <b>Če je konfigurirana</b>, bo aplikacija samodejno dodelila vloge na podlagi članstva v skupini uporabnika, pod pogojem, da so te skupine v zahtevku poimenovane 'admin', 'user' ali 'guest' brez razlikovanja med velikimi in malimi črkami. Zahtevek mora vsebovati seznam in če uporabnik pripada več skupinam, mu aplikacija dodeli vlogo, ki ustreza najvišjemu nivoju dostopa. Če se nobena skupina ne ujema, bo dostop zavrnjen.",
|
||||||
|
"LabelOpenRSSFeed": "Odpri vir RSS",
|
||||||
|
"LabelOverwrite": "Prepiši",
|
||||||
|
"LabelPassword": "Geslo",
|
||||||
|
"LabelPath": "Pot",
|
||||||
|
"LabelPermanent": "Trajno",
|
||||||
|
"LabelPermissionsAccessAllLibraries": "Lahko dostopa do vseh knjižnic",
|
||||||
|
"LabelPermissionsAccessAllTags": "Lahko dostopa do vseh oznak",
|
||||||
|
"LabelPermissionsAccessExplicitContent": "Lahko dostopa do eksplicitne vsebine",
|
||||||
|
"LabelPermissionsDelete": "Lahko briše",
|
||||||
|
"LabelPermissionsDownload": "Lahko prenaša",
|
||||||
|
"LabelPermissionsUpdate": "Lahko posodablja",
|
||||||
|
"LabelPermissionsUpload": "Lahko nalaga",
|
||||||
|
"LabelPersonalYearReview": "Pregled tvojega leta ({0})",
|
||||||
|
"LabelPhotoPathURL": "Slika pot/URL",
|
||||||
|
"LabelPlayMethod": "Metoda predvajanja",
|
||||||
|
"LabelPlayerChapterNumberMarker": "{0} od {1}",
|
||||||
|
"LabelPlaylists": "Seznami predvajanja",
|
||||||
|
"LabelPodcast": "Podcast",
|
||||||
|
"LabelPodcastSearchRegion": "Regija iskanja podcastov",
|
||||||
|
"LabelPodcastType": "Vrsta podcasta",
|
||||||
|
"LabelPodcasts": "Podcasti",
|
||||||
|
"LabelPort": "Vrata",
|
||||||
|
"LabelPrefixesToIgnore": "Predpone, ki jih je treba prezreti (neobčutljivo na velike in male črke)",
|
||||||
|
"LabelPreventIndexing": "Preprečite, da bi vaš vir indeksirali imeniki podcastov iTunes in Google",
|
||||||
|
"LabelPrimaryEbook": "Primarna eknjiga",
|
||||||
|
"LabelProgress": "Napredek",
|
||||||
|
"LabelProvider": "Ponudnik",
|
||||||
|
"LabelProviderAuthorizationValue": "Vrednost glave avtorizacije",
|
||||||
|
"LabelPubDate": "Datum objave",
|
||||||
|
"LabelPublishYear": "Leto objave",
|
||||||
|
"LabelPublishedDate": "Objavljeno {0}",
|
||||||
|
"LabelPublisher": "Založnik",
|
||||||
|
"LabelPublishers": "Založniki",
|
||||||
|
"LabelRSSFeedCustomOwnerEmail": "E-pošta lastnika po meri",
|
||||||
|
"LabelRSSFeedCustomOwnerName": "Ime lastnika po meri",
|
||||||
|
"LabelRSSFeedOpen": "Odprt vir RSS",
|
||||||
|
"LabelRSSFeedPreventIndexing": "Prepreči indeksiranje",
|
||||||
|
"LabelRSSFeedSlug": "Slug RSS vira",
|
||||||
|
"LabelRSSFeedURL": "URL vira RSS",
|
||||||
|
"LabelRandomly": "Naključno",
|
||||||
|
"LabelReAddSeriesToContinueListening": "Znova dodaj serijo za nadaljevanje poslušanja",
|
||||||
|
"LabelRead": "Preberi",
|
||||||
|
"LabelReadAgain": "Ponovno preberi",
|
||||||
|
"LabelReadEbookWithoutProgress": "Preberi eknjigo brez ohranjanja napredka",
|
||||||
|
"LabelRecentSeries": "Nedavne serije",
|
||||||
|
"LabelRecentlyAdded": "Nedavno dodano",
|
||||||
|
"LabelRecommended": "Priporočeno",
|
||||||
|
"LabelRedo": "Ponovi",
|
||||||
|
"LabelRegion": "Regija",
|
||||||
|
"LabelReleaseDate": "Datum izdaje",
|
||||||
|
"LabelRemoveCover": "Odstrani naslovnico",
|
||||||
|
"LabelRowsPerPage": "Vrstic na stran",
|
||||||
|
"LabelSearchTerm": "Iskalni pojem",
|
||||||
|
"LabelSearchTitle": "Naslov iskanja",
|
||||||
|
"LabelSearchTitleOrASIN": "Naslov iskanja ali ASIN",
|
||||||
|
"LabelSeason": "Sezona",
|
||||||
|
"LabelSelectAll": "Izberite vse",
|
||||||
|
"LabelSelectAllEpisodes": "Izberite vse epizode",
|
||||||
|
"LabelSelectEpisodesShowing": "Izberi {0} prikazanih epizod",
|
||||||
|
"LabelSelectUsers": "Izberite uporabnike",
|
||||||
|
"LabelSendEbookToDevice": "Pošlji eknjigo k...",
|
||||||
|
"LabelSequence": "Zaporedje",
|
||||||
|
"LabelSeries": "Serije",
|
||||||
|
"LabelSeriesName": "Ime serije",
|
||||||
|
"LabelSeriesProgress": "Napredek serije",
|
||||||
|
"LabelServerYearReview": "Pregled leta strežnika ({0})",
|
||||||
|
"LabelSetEbookAsPrimary": "Nastavi kot primarno",
|
||||||
|
"LabelSetEbookAsSupplementary": "Nastavi kot dodatno",
|
||||||
|
"LabelSettingsAudiobooksOnly": "Samo zvočne knjige",
|
||||||
|
"LabelSettingsAudiobooksOnlyHelp": "Če omogočite to nastavitev, bodo datoteke eknjig prezrte, razen če so znotraj mape zvočnih knjig, v tem primeru bodo nastavljene kot dodatne e-knjige",
|
||||||
|
"LabelSettingsBookshelfViewHelp": "Skeuomorfna oblika z lesenimi policami",
|
||||||
|
"LabelSettingsChromecastSupport": "Podpora za Chromecast",
|
||||||
|
"LabelSettingsDateFormat": "Oblika datuma",
|
||||||
|
"LabelSettingsDisableWatcher": "Onemogoči pregledovalca",
|
||||||
|
"LabelSettingsDisableWatcherForLibrary": "Onemogoči pregledovalca map za knjižnico",
|
||||||
|
"LabelSettingsDisableWatcherHelp": "Onemogoči samodejno dodajanje/posodabljanje elementov, ko so zaznane spremembe datoteke. *Potreben je ponovni zagon strežnika",
|
||||||
|
"LabelSettingsEnableWatcher": "Omogoči pregledovalca",
|
||||||
|
"LabelSettingsEnableWatcherForLibrary": "Omogoči pregledovalca map za knjižnico",
|
||||||
|
"LabelSettingsEnableWatcherHelp": "Omogoča samodejno dodajanje/posodabljanje elementov, ko so zaznane spremembe datoteke. *Potreben je ponovni zagon strežnika",
|
||||||
|
"LabelSettingsEpubsAllowScriptedContent": "Dovoli skriptirano vsebino v epubih",
|
||||||
|
"LabelSettingsEpubsAllowScriptedContentHelp": "Dovoli datotekam epub izvajanje skript. Priporočljivo je, da to nastavitev pustite onemogočeno, razen če zaupate viru datotek epub.",
|
||||||
|
"LabelSettingsExperimentalFeatures": "Eksperimentalne funkcije",
|
||||||
|
"LabelSettingsExperimentalFeaturesHelp": "Funkcije v razvoju, ki bi lahko uporabile vaše povratne informacije in pomoč pri testiranju. Kliknite, da odprete razpravo na githubu.",
|
||||||
|
"LabelSettingsFindCovers": "Poišči naslovnice",
|
||||||
|
"LabelSettingsFindCoversHelp": "Če vaša zvočna knjiga nima vdelane naslovnice ali slike naslovnice v mapi, bo pregledovalnik poskušal najti naslovnico.<br>Opomba: To bo podaljšalo čas pregledovanja",
|
||||||
|
"LabelSettingsHideSingleBookSeries": "Skrij serije s samo eno knjigo",
|
||||||
|
"LabelSettingsHideSingleBookSeriesHelp": "Serije, ki imajo eno knjigo, bodo skrite na strani serije in policah domače strani.",
|
||||||
|
"LabelSettingsHomePageBookshelfView": "Domača stran bo imela pogled knjižne police",
|
||||||
|
"LabelSettingsLibraryBookshelfView": "Knjižnična uporaba pogleda knjižne police",
|
||||||
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči prejšnje knjige v nadaljevanju serije",
|
||||||
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Polica z domačo stranjo Nadaljuj serijo prikazuje prvo nezačeto knjigo v seriji, ki ima vsaj eno dokončano knjigo in ni nobene knjige v teku. Če omogočite to nastavitev, se bo serija nadaljevala od najbolj dokončane knjige namesto od prve nezačete knjige.",
|
||||||
|
"LabelSettingsParseSubtitles": "Uporabi podnapise",
|
||||||
|
"LabelSettingsParseSubtitlesHelp": "Izvleci podnapise iz imen map zvočnih knjig.<br>Podnaslov mora biti ločen z \" - \"<br>npr. »Naslov knjige – Tu podnapis« ima podnaslov »Tu podnapis«",
|
||||||
|
"LabelSettingsPreferMatchedMetadata": "Prednost imajo ujemajoči se metapodatki",
|
||||||
|
"LabelSettingsPreferMatchedMetadataHelp": "Pri uporabi hitrega ujemanja bodo ujemajoči se podatki preglasili podrobnosti artikla. Hitro ujemanje bo privzeto izpolnil samo manjkajoče podrobnosti.",
|
||||||
|
"LabelSettingsSkipMatchingBooksWithASIN": "Preskoči ujemajoče se knjige, ki že imajo ASIN",
|
||||||
|
"LabelSettingsSkipMatchingBooksWithISBN": "Preskoči ujemajoče se knjige, ki že imajo oznako ISBN",
|
||||||
|
"LabelSettingsSortingIgnorePrefixes": "Pri razvrščanju ne upoštevajte predpon",
|
||||||
|
"LabelSettingsSortingIgnorePrefixesHelp": "npr. za naslov knjige s predpono \"the\" bi se \"The Book Title\" razvrstil kot \"Book Title, The\"",
|
||||||
|
"LabelSettingsSquareBookCovers": "Uporabi kvadratne platnice knjig",
|
||||||
|
"LabelSettingsSquareBookCoversHelp": "Raje uporabi kvadratne platnice kot standardne knjižne platnice 1.6:1",
|
||||||
|
"LabelSettingsStoreCoversWithItem": "Shrani naslovnice skupaj z elementom",
|
||||||
|
"LabelSettingsStoreCoversWithItemHelp": "Naslovnice so privzeto shranjene v /metadata/items, če omogočite to nastavitev, bodo platnice shranjene v mapi elementov knjižnice. Shranjena bo samo ena datoteka z imenom \"cover\"",
|
||||||
|
"LabelSettingsStoreMetadataWithItem": "Shrani metapodatke skupaj z elementom",
|
||||||
|
"LabelSettingsStoreMetadataWithItemHelp": "Datoteke z metapodatki so privzeto shranjene v /metadata/items, če omogočite to nastavitev, boste datoteke z metapodatki shranili v mape elementov vaše knjižnice",
|
||||||
|
"LabelSettingsTimeFormat": "Oblika časa",
|
||||||
|
"LabelShare": "Deli",
|
||||||
|
"LabelShareOpen": "Deli odprto",
|
||||||
|
"LabelShareURL": "Deli URL",
|
||||||
|
"LabelShowAll": "Prikaži vse",
|
||||||
|
"LabelShowSeconds": "Prikaži sekunde",
|
||||||
|
"LabelShowSubtitles": "Prikaži podnapise",
|
||||||
|
"LabelSize": "Velikost",
|
||||||
|
"LabelSleepTimer": "Časovnik za spanje",
|
||||||
|
"LabelSlug": "Slug",
|
||||||
|
"LabelStart": "Začetek",
|
||||||
|
"LabelStartTime": "Začetni čas",
|
||||||
|
"LabelStarted": "Začeto",
|
||||||
|
"LabelStartedAt": "Začeto ob",
|
||||||
|
"LabelStatsAudioTracks": "Zvočni posnetki",
|
||||||
|
"LabelStatsAuthors": "Avtorji",
|
||||||
|
"LabelStatsBestDay": "Najboljši dan",
|
||||||
|
"LabelStatsDailyAverage": "Dnevno povprečje",
|
||||||
|
"LabelStatsDays": "Dnevi",
|
||||||
|
"LabelStatsDaysListened": "Poslušani dnevi",
|
||||||
|
"LabelStatsHours": "Ure",
|
||||||
|
"LabelStatsInARow": "v vrsti",
|
||||||
|
"LabelStatsItemsFinished": "Končani elementi",
|
||||||
|
"LabelStatsItemsInLibrary": "Elementi v knjižnici",
|
||||||
|
"LabelStatsMinutes": "minute",
|
||||||
|
"LabelStatsMinutesListening": "Poslušane minute",
|
||||||
|
"LabelStatsOverallDays": "Skupaj dnevi",
|
||||||
|
"LabelStatsOverallHours": "Skupaj ure",
|
||||||
|
"LabelStatsWeekListening": "Tednov poslušanja",
|
||||||
|
"LabelSubtitle": "Podnapis",
|
||||||
|
"LabelSupportedFileTypes": "Podprte vrste datotek",
|
||||||
|
"LabelTag": "Oznaka",
|
||||||
|
"LabelTags": "Oznake",
|
||||||
|
"LabelTagsAccessibleToUser": "Oznake, dostopne uporabniku",
|
||||||
|
"LabelTagsNotAccessibleToUser": "Oznake, ki niso dostopne uporabniku",
|
||||||
|
"LabelTasks": "Tekoče naloge",
|
||||||
|
"LabelTextEditorBulletedList": "Seznam z oznakami",
|
||||||
|
"LabelTextEditorLink": "Povezava",
|
||||||
|
"LabelTextEditorNumberedList": "Številčni seznam",
|
||||||
|
"LabelTextEditorUnlink": "Odveži",
|
||||||
|
"LabelTheme": "Tema",
|
||||||
|
"LabelThemeDark": "Temna",
|
||||||
|
"LabelThemeLight": "Svetla",
|
||||||
|
"LabelTimeBase": "Odvisna od časa",
|
||||||
|
"LabelTimeDurationXHours": "{0} ur",
|
||||||
|
"LabelTimeDurationXMinutes": "{0} minut",
|
||||||
|
"LabelTimeDurationXSeconds": "{0} sekund",
|
||||||
|
"LabelTimeInMinutes": "Čas v minutah",
|
||||||
|
"LabelTimeListened": "Čas poslušanja",
|
||||||
|
"LabelTimeListenedToday": "Čas poslušanja danes",
|
||||||
|
"LabelTimeRemaining": "Še {0}",
|
||||||
|
"LabelTimeToShift": "Čas prestavljanja v sekundah",
|
||||||
|
"LabelTitle": "Naslov",
|
||||||
|
"LabelToolsEmbedMetadata": "Vdelaj metapodatke",
|
||||||
|
"LabelToolsEmbedMetadataDescription": "Vdelajte metapodatke v zvočne datoteke, vključno s sliko naslovnice in poglavji.",
|
||||||
|
"LabelToolsMakeM4b": "Ustvari datoteko zvočne knjige M4B",
|
||||||
|
"LabelToolsMakeM4bDescription": "Ustvarite datoteko zvočne knjige .M4B z vdelanimi metapodatki, sliko naslovnice in poglavji.",
|
||||||
|
"LabelToolsSplitM4b": "Razdeli M4B v MP3 datoteke",
|
||||||
|
"LabelToolsSplitM4bDescription": "Ustvarite MP3 datoteke iz datoteke M4B, razdeljene po poglavjih z vdelanimi metapodatki, naslovno sliko in poglavji.",
|
||||||
|
"LabelTotalDuration": "Skupno trajanje",
|
||||||
|
"LabelTotalTimeListened": "Skupni čas poslušanja",
|
||||||
|
"LabelTrackFromFilename": "Posnetek iz datoteke",
|
||||||
|
"LabelTrackFromMetadata": "Posnetek iz metapodatkov",
|
||||||
|
"LabelTracks": "Posnetki",
|
||||||
|
"LabelTracksMultiTrack": "Več posnetkov",
|
||||||
|
"LabelTracksNone": "Brez posnetka",
|
||||||
|
"LabelTracksSingleTrack": "Enojni posnetek",
|
||||||
|
"LabelType": "Vrsta",
|
||||||
|
"LabelUnabridged": "Neskrajšano",
|
||||||
|
"LabelUndo": "Razveljavi",
|
||||||
|
"LabelUnknown": "Neznano",
|
||||||
|
"LabelUnknownPublishDate": "Neznan datum objave",
|
||||||
|
"LabelUpdateCover": "Posodobi naslovnico",
|
||||||
|
"LabelUpdateCoverHelp": "Dovoli prepisovanje obstoječih naslovnic za izbrane knjige, ko se najde ujemanje",
|
||||||
|
"LabelUpdateDetails": "Posodobi podrobnosti",
|
||||||
|
"LabelUpdateDetailsHelp": "Dovoli prepisovanje obstoječih podrobnosti za izbrane knjige, ko se najde ujemanje",
|
||||||
|
"LabelUpdatedAt": "Posodobljeno ob",
|
||||||
|
"LabelUploaderDragAndDrop": "Povleci in spusti datoteke ali mape",
|
||||||
|
"LabelUploaderDropFiles": "Spusti datoteke",
|
||||||
|
"LabelUploaderItemFetchMetadataHelp": "Samodejno pridobi naslov, avtorja in serijo",
|
||||||
|
"LabelUseChapterTrack": "Uporabi posnetek poglavij",
|
||||||
|
"LabelUseFullTrack": "Uporabi celoten posnetek",
|
||||||
|
"LabelUser": "Uporabnik",
|
||||||
|
"LabelUsername": "Uporabniško ime",
|
||||||
|
"LabelValue": "Vrednost",
|
||||||
|
"LabelVersion": "Verzija",
|
||||||
|
"LabelViewBookmarks": "Ogled zaznamkov",
|
||||||
|
"LabelViewChapters": "Ogled poglavij",
|
||||||
|
"LabelViewPlayerSettings": "Ogled nastavitev predvajalnika",
|
||||||
|
"LabelViewQueue": "Ogled čakalno vrsto predvajalnika",
|
||||||
|
"LabelVolume": "Glasnost",
|
||||||
|
"LabelWeekdaysToRun": "Delovni dnevi predvajanja",
|
||||||
|
"LabelXBooks": "{0} knjig",
|
||||||
|
"LabelXItems": "{0} elementov",
|
||||||
|
"LabelYearReviewHide": "Skrij pregled leta",
|
||||||
|
"LabelYearReviewShow": "Poglej pregled leta",
|
||||||
|
"LabelYourAudiobookDuration": "Trajanje tvojih zvočnih knjig",
|
||||||
|
"LabelYourBookmarks": "Tvoji zaznamki",
|
||||||
|
"LabelYourPlaylists": "Tvoje seznami predvajanj",
|
||||||
|
"LabelYourProgress": "Tvoj napredek",
|
||||||
|
"MessageAddToPlayerQueue": "Dodaj v čakalno vrsto predvajalnika",
|
||||||
|
"MessageAppriseDescription": "Če želite uporabljati to funkcijo, morate imeti zagnan primerek <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">API Apprise</a> ali API, ki bo obravnaval te iste zahteve. <br />Url API-ja Apprise mora biti celotna pot URL-ja za pošiljanje obvestila, npr. če je vaš primerek API-ja postrežen na <code>http://192.168.1.1:8337</code>, bi morali vnesti <code >http://192.168.1.1:8337/notify</code>.",
|
||||||
|
"MessageBackupsDescription": "Varnostne kopije vključujejo uporabnike, napredek uporabnikov, podrobnosti elementov knjižnice, nastavitve strežnika in slike, shranjene v <code>/metadata/items</code> & <code>/metadata/authors</code>. Varnostne kopije <strong>ne</strong> vključujejo datotek, shranjenih v mapah vaše knjižnice.",
|
||||||
|
"MessageBackupsLocationEditNote": "Opomba: Posodabljanje lokacije varnostne kopije ne bo premaknilo ali spremenilo obstoječih varnostnih kopij",
|
||||||
|
"MessageBackupsLocationNoEditNote": "Opomba: Lokacija varnostne kopije je nastavljena s spremenljivko okolja in je tu ni mogoče spremeniti.",
|
||||||
|
"MessageBackupsLocationPathEmpty": "Pot do lokacije varnostne kopije ne sme biti prazna",
|
||||||
|
"MessageBatchQuickMatchDescription": "Hitro ujemanje bo poskušal dodati manjkajoče naslovnice in metapodatke za izbrane elemente. Omogočite spodnje možnosti, da omogočite hitremu ujemanju, da prepiše obstoječe naslovnice in/ali metapodatke.",
|
||||||
|
"MessageBookshelfNoCollections": "Ustvaril nisi še nobene zbirke",
|
||||||
|
"MessageBookshelfNoRSSFeeds": "Noben vir RSS ni odprt",
|
||||||
|
"MessageBookshelfNoResultsForFilter": "Ni rezultatov za filter \"{0}: {1}\"",
|
||||||
|
"MessageBookshelfNoResultsForQuery": "Ni rezultatov za poizvedbo",
|
||||||
|
"MessageBookshelfNoSeries": "Nimate serij",
|
||||||
|
"MessageChapterEndIsAfter": "Konec poglavja je za koncem vaše zvočne knjige",
|
||||||
|
"MessageChapterErrorFirstNotZero": "Prvo poglavje se mora začeti pri 0",
|
||||||
|
"MessageChapterErrorStartGteDuration": "Neveljaven začetni čas mora biti krajši od trajanja zvočne knjige",
|
||||||
|
"MessageChapterErrorStartLtPrev": "Neveljaven začetni čas mora biti večji od ali enak začetnemu času prejšnjega poglavja",
|
||||||
|
"MessageChapterStartIsAfter": "Začetek poglavja je po koncu vaše zvočne knjige",
|
||||||
|
"MessageCheckingCron": "Preverjam cron...",
|
||||||
|
"MessageConfirmCloseFeed": "Ali ste prepričani, da želite zapreti ta vir?",
|
||||||
|
"MessageConfirmDeleteBackup": "Ali ste prepričani, da želite izbrisati varnostno kopijo za {0}?",
|
||||||
|
"MessageConfirmDeleteDevice": "Ali ste prepričani, da želite izbrisati e-bralnik \"{0}\"?",
|
||||||
|
"MessageConfirmDeleteFile": "To bo izbrisalo datoteko iz vašega datotečnega sistema. Ali ste prepričani?",
|
||||||
|
"MessageConfirmDeleteLibrary": "Ali ste prepričani, da želite trajno izbrisati knjižnico \"{0}\"?",
|
||||||
|
"MessageConfirmDeleteLibraryItem": "S tem boste element knjižnice izbrisali iz baze podatkov in vašega datotečnega sistema. Ste prepričani?",
|
||||||
|
"MessageConfirmDeleteLibraryItems": "To bo izbrisalo {0} elementov knjižnice iz baze podatkov in vašega datotečnega sistema. Ste prepričani?",
|
||||||
|
"MessageConfirmDeleteMetadataProvider": "Ali ste prepričani, da želite izbrisati ponudnika metapodatkov po meri \"{0}\"?",
|
||||||
|
"MessageConfirmDeleteNotification": "Ali ste prepričani, da želite izbrisati to obvestilo?",
|
||||||
|
"MessageConfirmDeleteSession": "Ali ste prepričani, da želite izbrisati to sejo?",
|
||||||
|
"MessageConfirmForceReScan": "Ali ste prepričani, da želite vsiliti ponovno iskanje?",
|
||||||
|
"MessageConfirmMarkAllEpisodesFinished": "Ali ste prepričani, da želite označiti vse epizode kot dokončane?",
|
||||||
|
"MessageConfirmMarkAllEpisodesNotFinished": "Ali ste prepričani, da želite vse epizode označiti kot nedokončane?",
|
||||||
|
"MessageConfirmMarkItemFinished": "Ali ste prepričani, da želite \"{0}\" označiti kot dokončanega?",
|
||||||
|
"MessageConfirmMarkItemNotFinished": "Ali ste prepričani, da želite \"{0}\" označiti kot nedokončanega?",
|
||||||
|
"MessageConfirmMarkSeriesFinished": "Ali ste prepričani, da želite vse knjige v tej seriji označiti kot dokončane?",
|
||||||
|
"MessageConfirmMarkSeriesNotFinished": "Ali ste prepričani, da želite vse knjige v tej seriji označiti kot nedokončane?",
|
||||||
|
"MessageConfirmNotificationTestTrigger": "Želite sprožiti to obvestilo s testnimi podatki?",
|
||||||
|
"MessageConfirmPurgeCache": "Čiščenje predpomnilnika bo izbrisalo celoten imenik v <code>/metadata/cache</code>. <br /><br />Ali ste prepričani, da želite odstraniti imenik predpomnilnika?",
|
||||||
|
"MessageConfirmPurgeItemsCache": "Čiščenje predpomnilnika elementov bo izbrisalo celoten imenik na <code>/metadata/cache/items</code>.<br />Ste prepričani?",
|
||||||
|
"MessageConfirmQuickEmbed": "Opozorilo! Hitra vdelava ne bo varnostno kopirala vaših zvočnih datotek. Prepričajte se, da imate varnostno kopijo zvočnih datotek. <br><br>Ali želite nadaljevati?",
|
||||||
|
"MessageConfirmReScanLibraryItems": "Ali ste prepričani, da želite ponovno poiskati {0} elementov?",
|
||||||
|
"MessageConfirmRemoveAllChapters": "Ali ste prepričani, da želite odstraniti vsa poglavja?",
|
||||||
|
"MessageConfirmRemoveAuthor": "Ali ste prepričani, da želite odstraniti avtorja \"{0}\"?",
|
||||||
|
"MessageConfirmRemoveCollection": "Ali ste prepričani, da želite odstraniti zbirko \"{0}\"?",
|
||||||
|
"MessageConfirmRemoveEpisode": "Ali ste prepričani, da želite odstraniti epizodo \"{0}\"?",
|
||||||
|
"MessageConfirmRemoveEpisodes": "Ali ste prepričani, da želite odstraniti {0} epizod?",
|
||||||
|
"MessageConfirmRemoveListeningSessions": "Ali ste prepričani, da želite odstraniti {0} sej poslušanja?",
|
||||||
|
"MessageConfirmRemoveNarrator": "Ali ste prepričani, da želite odstraniti bralca \"{0}\"?",
|
||||||
|
"MessageConfirmRemovePlaylist": "Ali ste prepričani, da želite odstraniti svoj seznam predvajanja \"{0}\"?",
|
||||||
|
"MessageConfirmRenameGenre": "Ali ste prepričani, da želite preimenovati žanr \"{0}\" v \"{1}\" za vse elemente?",
|
||||||
|
"MessageConfirmRenameGenreMergeNote": "Opomba: Ta žanr že obstaja, zato bosta združeni.",
|
||||||
|
"MessageConfirmRenameGenreWarning": "Opozorilo! Podoben žanr z različnimi velikosti črk že obstaja \"{0}\".",
|
||||||
|
"MessageConfirmRenameTag": "Ali ste prepričani, da želite preimenovati oznako \"{0}\" v \"{1}\" za vse elemente?",
|
||||||
|
"MessageConfirmRenameTagMergeNote": "Opomba: Ta oznaka že obstaja, zato bosta združeni.",
|
||||||
|
"MessageConfirmRenameTagWarning": "Opozorilo! Podobna oznaka z različnimi velikosti črk že obstaja \"{0}\".",
|
||||||
|
"MessageConfirmResetProgress": "Ali ste prepričani, da želite ponastaviti svoj napredek?",
|
||||||
|
"MessageConfirmSendEbookToDevice": "Ali ste prepričani, da želite poslati {0} e-knjigo \"{1}\" v napravo \"{2}\"?",
|
||||||
|
"MessageConfirmUnlinkOpenId": "Ali ste prepričani, da želite prekiniti povezavo tega uporabnika z OpenID?",
|
||||||
|
"MessageDownloadingEpisode": "Prenašam epizodo",
|
||||||
|
"MessageDragFilesIntoTrackOrder": "Povlecite datoteke v pravilen vrstni red posnetkov",
|
||||||
|
"MessageEmbedFailed": "Vdelava ni uspela!",
|
||||||
|
"MessageEmbedFinished": "Vdelava končana!",
|
||||||
|
"MessageEpisodesQueuedForDownload": "{0} epizod v čakalni vrsti za prenos",
|
||||||
|
"MessageEreaderDevices": "Da zagotovite dostavo e-knjig, boste morda morali dodati zgornji e-poštni naslov kot veljavnega pošiljatelja za vsako spodaj navedeno napravo.",
|
||||||
|
"MessageFeedURLWillBe": "URL vira bo {0}",
|
||||||
|
"MessageFetching": "Pridobivam...",
|
||||||
|
"MessageForceReScanDescription": "bo znova pregledal vse datoteke kot nov pregled. Oznake ID3 zvočnih datotek, datoteke OPF in besedilne datoteke bodo pregledane kot nove.",
|
||||||
|
"MessageImportantNotice": "Pomembno obvestilo!",
|
||||||
|
"MessageInsertChapterBelow": "Spodaj vstavite poglavje",
|
||||||
|
"MessageItemsSelected": "{0} izbranih elementov",
|
||||||
|
"MessageItemsUpdated": "Št. posodobljenih elementov: {0}",
|
||||||
|
"MessageJoinUsOn": "Pridružite se nam",
|
||||||
|
"MessageListeningSessionsInTheLastYear": "{0} sej poslušanja v zadnjem letu",
|
||||||
|
"MessageLoading": "Nalagam...",
|
||||||
|
"MessageLoadingFolders": "Nalagam mape...",
|
||||||
|
"MessageLogsDescription": "Dnevniki so shranjeni v <code>/metadata/logs</code> kot datoteke JSON. Dnevniki zrušitev so shranjeni v <code>/metadata/logs/crash_logs.txt</code>.",
|
||||||
|
"MessageM4BFailed": "M4B ni uspel!",
|
||||||
|
"MessageM4BFinished": "M4B končan!",
|
||||||
|
"MessageMapChapterTitles": "Preslikajte naslove poglavij v obstoječa poglavja zvočne knjige brez prilagajanja časovnih žigov",
|
||||||
|
"MessageMarkAllEpisodesFinished": "Označi vse epizode kot končane",
|
||||||
|
"MessageMarkAllEpisodesNotFinished": "Označi vse epizode kot nedokončane",
|
||||||
|
"MessageMarkAsFinished": "Označi kot dokončano",
|
||||||
|
"MessageMarkAsNotFinished": "Označi kot nedokončano",
|
||||||
|
"MessageMatchBooksDescription": "bo poskušal povezati knjige v knjižnici s knjigo izbranega ponudnika iskanja in izpolniti prazne podatke in naslovnico. Ne prepisujejo se pa podrobnosti.",
|
||||||
|
"MessageNoAudioTracks": "Ni zvočnih posnetkov",
|
||||||
|
"MessageNoAuthors": "Brez avtorjev",
|
||||||
|
"MessageNoBackups": "Brez varnostnih kopij",
|
||||||
|
"MessageNoBookmarks": "Brez zaznamkov",
|
||||||
|
"MessageNoChapters": "Brez poglavij",
|
||||||
|
"MessageNoCollections": "Brez zbirk",
|
||||||
|
"MessageNoCoversFound": "Ni naslovnic",
|
||||||
|
"MessageNoDescription": "Ni opisa",
|
||||||
|
"MessageNoDevices": "Ni naprav",
|
||||||
|
"MessageNoDownloadsInProgress": "Trenutno ni prenosov v teku",
|
||||||
|
"MessageNoDownloadsQueued": "Ni prenosov v čakalni vrsti",
|
||||||
|
"MessageNoEpisodeMatchesFound": "Ni zadetkov za epizodo",
|
||||||
|
"MessageNoEpisodes": "Ni epizod",
|
||||||
|
"MessageNoFoldersAvailable": "Ni na voljo nobene mape",
|
||||||
|
"MessageNoGenres": "Ni žanrov",
|
||||||
|
"MessageNoIssues": "Ni težav",
|
||||||
|
"MessageNoItems": "Ni elementov",
|
||||||
|
"MessageNoItemsFound": "Ni najdenih elementov",
|
||||||
|
"MessageNoListeningSessions": "Ni sej poslušanja",
|
||||||
|
"MessageNoLogs": "Ni dnevnikov",
|
||||||
|
"MessageNoMediaProgress": "Ni medijskega napredka",
|
||||||
|
"MessageNoNotifications": "Ni obvestil",
|
||||||
|
"MessageNoPodcastsFound": "Ni podcastov",
|
||||||
|
"MessageNoResults": "Ni rezultatov",
|
||||||
|
"MessageNoSearchResultsFor": "Ni rezultatov iskanja za \"{0}\"",
|
||||||
|
"MessageNoSeries": "Ni serij",
|
||||||
|
"MessageNoTags": "Ni oznak",
|
||||||
|
"MessageNoTasksRunning": "Nobeno opravili ne teče",
|
||||||
|
"MessageNoUpdatesWereNecessary": "Posodobitve niso bile potrebne",
|
||||||
|
"MessageNoUserPlaylists": "Nimate seznamov predvajanja",
|
||||||
|
"MessageNotYetImplemented": "Še ni implementirano",
|
||||||
|
"MessageOpmlPreviewNote": "Opomba: To je predogled razčlenjene datoteke OPML. Dejanski naslov podcasta bo vzet iz vira RSS.",
|
||||||
|
"MessageOr": "ali",
|
||||||
|
"MessagePauseChapter": "Začasno ustavite predvajanje poglavja",
|
||||||
|
"MessagePlayChapter": "Poslušajte začetek poglavja",
|
||||||
|
"MessagePlaylistCreateFromCollection": "Ustvari seznam predvajanja iz zbirke",
|
||||||
|
"MessagePleaseWait": "Prosim počakajte...",
|
||||||
|
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nima URL-ja vira RSS, ki bi ga lahko uporabil za ujemanje",
|
||||||
|
"MessageQuickMatchDescription": "Izpolni prazne podrobnosti elementa in naslovnico s prvim rezultatom ujemanja iz '{0}'. Ne prepiše podrobnosti, razen če je omogočena nastavitev strežnika 'Prednostno ujemajoči se metapodatki'.",
|
||||||
|
"MessageRemoveChapter": "Odstrani poglavje",
|
||||||
|
"MessageRemoveEpisodes": "Odstrani toliko epizod: {0}",
|
||||||
|
"MessageRemoveFromPlayerQueue": "Odstrani iz čakalne vrste predvajalnika",
|
||||||
|
"MessageRemoveUserWarning": "Ali ste prepričani, da želite trajno izbrisati uporabnika \"{0}\"?",
|
||||||
|
"MessageReportBugsAndContribute": "Prijavite hrošče, zahtevajte nove funkcije in prispevajte še naprej",
|
||||||
|
"MessageResetChaptersConfirm": "Ali ste prepričani, da želite ponastaviti poglavja in razveljaviti spremembe, ki ste jih naredili?",
|
||||||
|
"MessageRestoreBackupConfirm": "Ali ste prepričani, da želite obnoviti varnostno kopijo, ustvarjeno ob",
|
||||||
|
"MessageRestoreBackupWarning": "Obnovitev varnostne kopije bo prepisala celotno zbirko podatkov, ki se nahaja v /config, in zajema slike v /metadata/items in /metadata/authors.<br /><br />Varnostne kopije ne spreminjajo nobenih datotek v mapah vaše knjižnice. Če ste omogočili nastavitve strežnika za shranjevanje naslovnic in metapodatkov v mapah vaše knjižnice, potem ti niso varnostno kopirani ali prepisani.<br /><br />Vsi odjemalci, ki uporabljajo vaš strežnik, bodo samodejno osveženi.",
|
||||||
|
"MessageSearchResultsFor": "Rezultati iskanja za",
|
||||||
|
"MessageSelected": "{0} izbrano",
|
||||||
|
"MessageServerCouldNotBeReached": "Strežnika ni bilo mogoče doseči",
|
||||||
|
"MessageSetChaptersFromTracksDescription": "Nastavite poglavja z uporabo vsake zvočne datoteke kot poglavja in naslova poglavja kot imena zvočne datoteke",
|
||||||
|
"MessageShareExpirationWillBe": "Potečeno bo <strong>{0}</strong>",
|
||||||
|
"MessageShareExpiresIn": "Poteče čez {0}",
|
||||||
|
"MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>",
|
||||||
|
"MessageStartPlaybackAtTime": "Začni predvajanje za \"{0}\" ob {1}?",
|
||||||
|
"MessageThinking": "Razmišljam...",
|
||||||
|
"MessageUploaderItemFailed": "Nalaganje ni uspelo",
|
||||||
|
"MessageUploaderItemSuccess": "Uspešno naloženo!",
|
||||||
|
"MessageUploading": "Nalaganje...",
|
||||||
|
"MessageValidCronExpression": "Veljaven cron izraz",
|
||||||
|
"MessageWatcherIsDisabledGlobally": "Pregledovalec je globalno onemogočen v nastavitvah strežnika",
|
||||||
|
"MessageXLibraryIsEmpty": "{0} Knjižnica je prazna!",
|
||||||
|
"MessageYourAudiobookDurationIsLonger": "Trajanje vaše zvočne knjige je daljše od ugotovljenega trajanja",
|
||||||
|
"MessageYourAudiobookDurationIsShorter": "Trajanje vaše zvočne knjige je krajše od ugotovljenega trajanja",
|
||||||
|
"NoteChangeRootPassword": "Korenski uporabnik je edini uporabnik, ki ima lahko prazno geslo",
|
||||||
|
"NoteChapterEditorTimes": "Opomba: Začetni čas prvega poglavja mora ostati pri 0:00 in zadnji čas začetka poglavja ne sme preseči tega trajanja zvočne knjige.",
|
||||||
|
"NoteFolderPicker": "Opomba: že preslikane mape ne bodo prikazane",
|
||||||
|
"NoteRSSFeedPodcastAppsHttps": "Opozorilo: večina aplikacij za podcaste bo zahtevala, da URL vira RSS uporablja HTTPS",
|
||||||
|
"NoteRSSFeedPodcastAppsPubDate": "Opozorilo: 1 ali več vaših epizod nima datuma objave. Nekatere aplikacije za podcaste to zahtevajo.",
|
||||||
|
"NoteUploaderFoldersWithMediaFiles": "Mape z predstavnostnimi datotekami bodo obravnavane kot ločene postavke knjižnice.",
|
||||||
|
"NoteUploaderOnlyAudioFiles": "Če nalagate samo zvočne datoteke, bo vsaka zvočna datoteka obravnavana kot ločena zvočna knjiga.",
|
||||||
|
"NoteUploaderUnsupportedFiles": "Nepodprte datoteke so prezrte. Ko izberete ali spustite mapo, se druge datoteke, ki niso v mapi elementov, prezrejo.",
|
||||||
|
"PlaceholderNewCollection": "Novo ime zbirke",
|
||||||
|
"PlaceholderNewFolderPath": "Pot nove mape",
|
||||||
|
"PlaceholderNewPlaylist": "Novo ime seznama predvajanja",
|
||||||
|
"PlaceholderSearch": "Poišči..",
|
||||||
|
"PlaceholderSearchEpisode": "Poišči epizodo...",
|
||||||
|
"StatsAuthorsAdded": "dodanih avtorjev",
|
||||||
|
"StatsBooksAdded": "dodanih knjig",
|
||||||
|
"StatsBooksAdditional": "Nekateri dodatki vključujejo…",
|
||||||
|
"StatsBooksFinished": "končane knjige",
|
||||||
|
"StatsBooksFinishedThisYear": "Nekaj knjig, ki so bile dokončane letos…",
|
||||||
|
"StatsBooksListenedTo": "poslušane knjige",
|
||||||
|
"StatsCollectionGrewTo": "Vaša zbirka knjig se je povečala na …",
|
||||||
|
"StatsSessions": "seje",
|
||||||
|
"StatsSpentListening": "porabil za poslušanje",
|
||||||
|
"StatsTopAuthor": "TOP AVTOR",
|
||||||
|
"StatsTopAuthors": "TOP AVTORJI",
|
||||||
|
"StatsTopGenre": "TOP ŽANR",
|
||||||
|
"StatsTopGenres": "TOP ŽANRI",
|
||||||
|
"StatsTopMonth": "TOP MESEC",
|
||||||
|
"StatsTopNarrator": "TOP BRALEC",
|
||||||
|
"StatsTopNarrators": "TOP BRALCI",
|
||||||
|
"StatsTotalDuration": "S skupnim trajanjem…",
|
||||||
|
"StatsYearInReview": "PREGLED LETA",
|
||||||
|
"ToastAccountUpdateFailed": "Računa ni bilo mogoče posodobiti",
|
||||||
|
"ToastAccountUpdateSuccess": "Račun posodobljen",
|
||||||
|
"ToastAppriseUrlRequired": "Vnesti morate Apprise URL",
|
||||||
|
"ToastAuthorImageRemoveSuccess": "Slika avtorja je odstranjena",
|
||||||
|
"ToastAuthorNotFound": "Avtor \"{0}\" ni bil najden",
|
||||||
|
"ToastAuthorRemoveSuccess": "Avtor odstranjen",
|
||||||
|
"ToastAuthorSearchNotFound": "Ne najdem avtorja",
|
||||||
|
"ToastAuthorUpdateFailed": "Avtorja ni bilo mogoče posodobiti",
|
||||||
|
"ToastAuthorUpdateMerged": "Avtor združen",
|
||||||
|
"ToastAuthorUpdateSuccess": "Avtor posodobljen",
|
||||||
|
"ToastAuthorUpdateSuccessNoImageFound": "Avtor posodobljen (ne najdem slike)",
|
||||||
|
"ToastBackupAppliedSuccess": "Uporabljena varnostna kopija",
|
||||||
|
"ToastBackupCreateFailed": "Varnostne kopije ni bilo mogoče ustvariti",
|
||||||
|
"ToastBackupCreateSuccess": "Varnostna kopija ustvarjena",
|
||||||
|
"ToastBackupDeleteFailed": "Varnostne kopije ni bilo mogoče izbrisati",
|
||||||
|
"ToastBackupDeleteSuccess": "Varnostna kopija izbrisana",
|
||||||
|
"ToastBackupInvalidMaxKeep": "Neveljavno število varnostnih kopij za ohranjanje",
|
||||||
|
"ToastBackupInvalidMaxSize": "Neveljavna največja velikost varnostne kopije",
|
||||||
|
"ToastBackupPathUpdateFailed": "Posodobitev poti varnostnih kopij ni uspela",
|
||||||
|
"ToastBackupRestoreFailed": "Varnostne kopije ni bilo mogoče obnoviti",
|
||||||
|
"ToastBackupUploadFailed": "Nalaganje varnostne kopije ni uspelo",
|
||||||
|
"ToastBackupUploadSuccess": "Varnostna kopija je naložena",
|
||||||
|
"ToastBatchDeleteFailed": "Paketno brisanje ni uspelo",
|
||||||
|
"ToastBatchDeleteSuccess": "Paketno brisanje je bilo uspešno",
|
||||||
|
"ToastBatchUpdateFailed": "Paketna posodobitev ni uspela",
|
||||||
|
"ToastBatchUpdateSuccess": "Paketna posodobitev je uspela",
|
||||||
|
"ToastBookmarkCreateFailed": "Zaznamka ni bilo mogoče ustvariti",
|
||||||
|
"ToastBookmarkCreateSuccess": "Zaznamek dodan",
|
||||||
|
"ToastBookmarkRemoveSuccess": "Zaznamek odstranjen",
|
||||||
|
"ToastBookmarkUpdateFailed": "Zaznamka ni bilo mogoče posodobiti",
|
||||||
|
"ToastBookmarkUpdateSuccess": "Zaznamek posodobljen",
|
||||||
|
"ToastCachePurgeFailed": "Čiščenje predpomnilnika ni uspelo",
|
||||||
|
"ToastCachePurgeSuccess": "Predpomnilnik je bil uspešno očiščen",
|
||||||
|
"ToastChaptersHaveErrors": "Poglavja imajo napake",
|
||||||
|
"ToastChaptersMustHaveTitles": "Poglavja morajo imeti naslove",
|
||||||
|
"ToastChaptersRemoved": "Poglavja so odstranjena",
|
||||||
|
"ToastCollectionItemsAddFailed": "Dodajanje elementov v zbirko ni uspelo",
|
||||||
|
"ToastCollectionItemsAddSuccess": "Dodajanje elementov v zbirko je bilo uspešno",
|
||||||
|
"ToastCollectionItemsRemoveSuccess": "Elementi so bili odstranjeni iz zbirke",
|
||||||
|
"ToastCollectionRemoveSuccess": "Zbirka je bila odstranjena",
|
||||||
|
"ToastCollectionUpdateFailed": "Zbirke ni bilo mogoče posodobiti",
|
||||||
|
"ToastCollectionUpdateSuccess": "Zbirka je bila posodobljena",
|
||||||
|
"ToastCoverUpdateFailed": "Posodobitev naslovnice ni uspela",
|
||||||
|
"ToastDeleteFileFailed": "Brisanje datoteke ni uspelo",
|
||||||
|
"ToastDeleteFileSuccess": "Datoteka je bila izbrisana",
|
||||||
|
"ToastDeviceAddFailed": "Naprave ni bilo mogoče dodati",
|
||||||
|
"ToastDeviceNameAlreadyExists": "Elektronska naprava s tem imenom že obstaja",
|
||||||
|
"ToastDeviceTestEmailFailed": "Pošiljanje testnega e-poštnega sporočila ni uspelo",
|
||||||
|
"ToastDeviceTestEmailSuccess": "Testno e-poštno sporočilo je poslano",
|
||||||
|
"ToastDeviceUpdateFailed": "Naprave ni bilo mogoče posodobiti",
|
||||||
|
"ToastEmailSettingsUpdateFailed": "E-poštnih nastavitev ni bilo mogoče posodobiti",
|
||||||
|
"ToastEmailSettingsUpdateSuccess": "E-poštne nastavitve so bile posodobljene",
|
||||||
|
"ToastEncodeCancelFailed": "Napaka pri preklicu prekodiranja",
|
||||||
|
"ToastEncodeCancelSucces": "Prekodiranje prekinjeno",
|
||||||
|
"ToastEpisodeDownloadQueueClearFailed": "Čiščenje čakalne vrste ni uspelo",
|
||||||
|
"ToastEpisodeDownloadQueueClearSuccess": "Čakalna vrsta za prenos epizod je počiščena",
|
||||||
|
"ToastErrorCannotShare": "V tej napravi ni mogoče dati v skupno rabo",
|
||||||
|
"ToastFailedToLoadData": "Podatkov ni bilo mogoče naložiti",
|
||||||
|
"ToastFailedToShare": "Skupna raba ni uspela",
|
||||||
|
"ToastFailedToUpdateAccount": "Računa ni bilo mogoče posodobiti",
|
||||||
|
"ToastFailedToUpdateUser": "Uporabnika ni bilo mogoče posodobiti",
|
||||||
|
"ToastInvalidImageUrl": "Neveljaven URL slike",
|
||||||
|
"ToastInvalidUrl": "Neveljaven URL",
|
||||||
|
"ToastItemCoverUpdateFailed": "Naslovnice elementa ni bilo mogoče posodobiti",
|
||||||
|
"ToastItemCoverUpdateSuccess": "Naslovnica elementa je bila posodobljena",
|
||||||
|
"ToastItemDeletedFailed": "Elementa ni bilo mogoče izbrisati",
|
||||||
|
"ToastItemDeletedSuccess": "Element je bil izbrisan",
|
||||||
|
"ToastItemDetailsUpdateFailed": "Posodobitev podrobnosti elementa ni uspela",
|
||||||
|
"ToastItemDetailsUpdateSuccess": "Podrobnosti elementa so bile posodobjene",
|
||||||
|
"ToastItemMarkedAsFinishedFailed": "Označevanje kot dokončano ni uspelo",
|
||||||
|
"ToastItemMarkedAsFinishedSuccess": "Element je označen kot dokončan",
|
||||||
|
"ToastItemMarkedAsNotFinishedFailed": "Ni bilo mogoče označiti kot nedokončano",
|
||||||
|
"ToastItemMarkedAsNotFinishedSuccess": "Element označen kot nedokončan",
|
||||||
|
"ToastItemUpdateFailed": "Elementa ni bilo mogoče posodobiti",
|
||||||
|
"ToastItemUpdateSuccess": "Element je bil posodobljen",
|
||||||
|
"ToastLibraryCreateFailed": "Knjižnice ni bilo mogoče ustvariti",
|
||||||
|
"ToastLibraryCreateSuccess": "Knjižnica \"{0}\" je bila ustvarjena",
|
||||||
|
"ToastLibraryDeleteFailed": "Knjižnice ni bilo mogoče izbrisati",
|
||||||
|
"ToastLibraryDeleteSuccess": "Knjižnica je bila izbrisana",
|
||||||
|
"ToastLibraryScanFailedToStart": "Pregleda ni bilo mogoče začeti",
|
||||||
|
"ToastLibraryScanStarted": "Pregled knjižnice se je začel",
|
||||||
|
"ToastLibraryUpdateFailed": "Knjižnice ni bilo mogoče posodobiti",
|
||||||
|
"ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" je bila posodobljena",
|
||||||
|
"ToastNameEmailRequired": "Ime in e-pošta sta obvezna",
|
||||||
|
"ToastNameRequired": "Ime je obvezno",
|
||||||
|
"ToastNewUserCreatedFailed": "Računa ni bilo mogoče ustvariti: \"{0}\"",
|
||||||
|
"ToastNewUserCreatedSuccess": "Nov račun je bil ustvarjen",
|
||||||
|
"ToastNewUserLibraryError": "Izbrati morate vsaj eno knjižnico",
|
||||||
|
"ToastNewUserPasswordError": "Mora imeti geslo, samo korenski uporabnik ima lahko prazno geslo",
|
||||||
|
"ToastNewUserTagError": "Izbrati morate vsaj eno oznako",
|
||||||
|
"ToastNewUserUsernameError": "Vnesite uporabniško ime",
|
||||||
|
"ToastNoUpdatesNecessary": "Posodobitve niso potrebne",
|
||||||
|
"ToastNotificationCreateFailed": "Obvestila ni bilo mogoče ustvariti",
|
||||||
|
"ToastNotificationDeleteFailed": "Brisanje obvestila ni uspelo",
|
||||||
|
"ToastNotificationFailedMaximum": "Največje število neuspelih poskusov mora biti >= 0",
|
||||||
|
"ToastNotificationQueueMaximum": "Največja čakalna vrsta obvestil mora biti >= 0",
|
||||||
|
"ToastNotificationSettingsUpdateFailed": "Nastavitev obvestil ni bilo mogoče posodobiti",
|
||||||
|
"ToastNotificationSettingsUpdateSuccess": "Nastavitve obvestil so bile posodobljene",
|
||||||
|
"ToastNotificationTestTriggerFailed": "Sprožitev testnega obvestila ni uspela",
|
||||||
|
"ToastNotificationTestTriggerSuccess": "Sproženo testno obvestilo",
|
||||||
|
"ToastNotificationUpdateFailed": "Obvestila ni bilo mogoče posodobiti",
|
||||||
|
"ToastNotificationUpdateSuccess": "Obvestilo posodobljeno",
|
||||||
|
"ToastPlaylistCreateFailed": "Seznama predvajanja ni bilo mogoče ustvariti",
|
||||||
|
"ToastPlaylistCreateSuccess": "Seznam predvajanja je bil ustvarjen",
|
||||||
|
"ToastPlaylistRemoveSuccess": "Seznam predvajanja odstranjen",
|
||||||
|
"ToastPlaylistUpdateFailed": "Seznama predvajanja ni bilo mogoče posodobiti",
|
||||||
|
"ToastPlaylistUpdateSuccess": "Seznam predvajanja je bil posodobljen",
|
||||||
|
"ToastPodcastCreateFailed": "Podcasta ni bilo mogoče ustvariti",
|
||||||
|
"ToastPodcastCreateSuccess": "Podcast je bil uspešno ustvarjen",
|
||||||
|
"ToastPodcastGetFeedFailed": "Vira podcasta ni bilo mogoče pridobiti",
|
||||||
|
"ToastPodcastNoEpisodesInFeed": "V viru RSS ni bilo mogoče najti nobene epizode",
|
||||||
|
"ToastPodcastNoRssFeed": "Podcast nima vira RSS",
|
||||||
|
"ToastProviderCreatedFailed": "Ponudnika ni bilo mogoče dodati",
|
||||||
|
"ToastProviderCreatedSuccess": "Dodan je bil nov ponudnik",
|
||||||
|
"ToastProviderNameAndUrlRequired": "Obvezen podatek sta ime in URL",
|
||||||
|
"ToastProviderRemoveSuccess": "Ponudnik je bil odstranjen",
|
||||||
|
"ToastRSSFeedCloseFailed": "Vira RSS ni bilo mogoče zapreti",
|
||||||
|
"ToastRSSFeedCloseSuccess": "Vir RSS je bil zaprt",
|
||||||
|
"ToastRemoveFailed": "Odstranitev ni uspela",
|
||||||
|
"ToastRemoveItemFromCollectionFailed": "Elementa ni bilo mogoče odstraniti iz zbirke",
|
||||||
|
"ToastRemoveItemFromCollectionSuccess": "Element je bil odstranjen iz zbirke",
|
||||||
|
"ToastRemoveItemsWithIssuesFailed": "Elementov knjižnice s težavami ni bilo mogoče odstraniti",
|
||||||
|
"ToastRemoveItemsWithIssuesSuccess": "Odstranjeni so bili elementi knjižnice s težavami",
|
||||||
|
"ToastRenameFailed": "Preimenovanje ni uspelo",
|
||||||
|
"ToastRescanFailed": "Ponovni pregled ni uspel za {0}",
|
||||||
|
"ToastRescanRemoved": "Ponovni pregled celotnega elementa je bil odstranjen",
|
||||||
|
"ToastRescanUpToDate": "Ponovni pregled celotnega elementa je bil ažuren",
|
||||||
|
"ToastRescanUpdated": "Ponovni pregled celotnega elementa je bil posodobljen",
|
||||||
|
"ToastScanFailed": "Pregled elementa knjižnice ni uspel",
|
||||||
|
"ToastSelectAtLeastOneUser": "Izberite vsaj enega uporabnika",
|
||||||
|
"ToastSendEbookToDeviceFailed": "E-knjige ni bilo mogoče poslati v napravo",
|
||||||
|
"ToastSendEbookToDeviceSuccess": "E-knjiga je bila poslana v napravo \"{0}\"",
|
||||||
|
"ToastSeriesUpdateFailed": "Posodobitev serije ni uspela",
|
||||||
|
"ToastSeriesUpdateSuccess": "Uspešna posodobitev serije",
|
||||||
|
"ToastServerSettingsUpdateFailed": "Nastavitev strežnika ni bilo mogoče posodobiti",
|
||||||
|
"ToastServerSettingsUpdateSuccess": "Nastavitve strežnika so bile posodobljene",
|
||||||
|
"ToastSessionCloseFailed": "Seje ni bilo mogoče zapreti",
|
||||||
|
"ToastSessionDeleteFailed": "Brisanje seje ni uspelo",
|
||||||
|
"ToastSessionDeleteSuccess": "Seja je bila izbrisana",
|
||||||
|
"ToastSlugMustChange": "Slug vsebuje neveljavne znake",
|
||||||
|
"ToastSlugRequired": "Slug je obvezen podatek",
|
||||||
|
"ToastSocketConnected": "Omrežna povezava je priklopljena",
|
||||||
|
"ToastSocketDisconnected": "Omrežna povezava je odklopljena",
|
||||||
|
"ToastSocketFailedToConnect": "Omrežna povezava ni uspela vzpostaviti priklopa",
|
||||||
|
"ToastSortingPrefixesEmptyError": "Imeti mora vsaj 1 predpono za razvrščanje",
|
||||||
|
"ToastSortingPrefixesUpdateFailed": "Posodobitev predpon za razvrščanje ni uspela",
|
||||||
|
"ToastSortingPrefixesUpdateSuccess": "Predpone za razvrščanje so bile posodobljene ({0} elementov)",
|
||||||
|
"ToastTitleRequired": "Naslov je obvezen",
|
||||||
|
"ToastUnknownError": "Neznana napaka",
|
||||||
|
"ToastUnlinkOpenIdFailed": "Prekinitev povezave uporabnika z OpenID ni uspela",
|
||||||
|
"ToastUnlinkOpenIdSuccess": "Uporabnik je prekinil povezavo z OpenID",
|
||||||
|
"ToastUserDeleteFailed": "Brisanje uporabnika ni uspelo",
|
||||||
|
"ToastUserDeleteSuccess": "Uporabnik je bil izbrisan",
|
||||||
|
"ToastUserPasswordChangeSuccess": "Geslo je bilo uspešno spremenjeno",
|
||||||
|
"ToastUserPasswordMismatch": "Gesli se ne ujemata",
|
||||||
|
"ToastUserPasswordMustChange": "Novo geslo se ne sme ujemati s starim geslom",
|
||||||
|
"ToastUserRootRequireName": "Vnesti morate korensko uporabniško ime"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.13.1",
|
"version": "2.13.3",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast server",
|
"description": "Self-hosted audiobook and podcast server",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
+1
-21
@@ -442,26 +442,6 @@ class Database {
|
|||||||
await this.models.feed.removeById(feedId)
|
await this.models.feed.removeById(feedId)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSeries(oldSeries) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
return this.models.series.updateFromOld(oldSeries)
|
|
||||||
}
|
|
||||||
|
|
||||||
async createSeries(oldSeries) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
await this.models.series.createFromOld(oldSeries)
|
|
||||||
}
|
|
||||||
|
|
||||||
async createBulkSeries(oldSeriesObjs) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
await this.models.series.createBulkFromOld(oldSeriesObjs)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeSeries(seriesId) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
await this.models.series.removeById(seriesId)
|
|
||||||
}
|
|
||||||
|
|
||||||
async createBulkBookAuthors(bookAuthors) {
|
async createBulkBookAuthors(bookAuthors) {
|
||||||
if (!this.sequelize) return false
|
if (!this.sequelize) return false
|
||||||
await this.models.bookAuthor.bulkCreate(bookAuthors)
|
await this.models.bookAuthor.bulkCreate(bookAuthors)
|
||||||
@@ -678,7 +658,7 @@ class Database {
|
|||||||
*/
|
*/
|
||||||
async getSeriesIdByName(libraryId, seriesName) {
|
async getSeriesIdByName(libraryId, seriesName) {
|
||||||
if (!this.libraryFilterData[libraryId]) {
|
if (!this.libraryFilterData[libraryId]) {
|
||||||
return (await this.seriesModel.getOldByNameAndLibrary(seriesName, libraryId))?.id || null
|
return (await this.seriesModel.getByNameAndLibrary(seriesName, libraryId))?.id || null
|
||||||
}
|
}
|
||||||
return this.libraryFilterData[libraryId].series.find((se) => se.name === seriesName)?.id || null
|
return this.libraryFilterData[libraryId].series.find((se) => se.name === seriesName)?.id || null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,9 @@ class AuthorController {
|
|||||||
let hasUpdated = false
|
let hasUpdated = false
|
||||||
|
|
||||||
const authorNameUpdate = payload.name !== undefined && payload.name !== req.author.name
|
const authorNameUpdate = payload.name !== undefined && payload.name !== req.author.name
|
||||||
|
if (authorNameUpdate) {
|
||||||
|
payload.lastFirst = Database.authorModel.getLastFirst(payload.name)
|
||||||
|
}
|
||||||
|
|
||||||
// Check if author name matches another author and merge the authors
|
// Check if author name matches another author and merge the authors
|
||||||
let existingAuthor = null
|
let existingAuthor = null
|
||||||
@@ -169,6 +172,11 @@ class AuthorController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If lastFirst is not set, get it from the name
|
||||||
|
if (!authorNameUpdate && !req.author.lastFirst) {
|
||||||
|
payload.lastFirst = Database.authorModel.getLastFirst(req.author.name)
|
||||||
|
}
|
||||||
|
|
||||||
// Regular author update
|
// Regular author update
|
||||||
req.author.set(payload)
|
req.author.set(payload)
|
||||||
if (req.author.changed()) {
|
if (req.author.changed()) {
|
||||||
|
|||||||
@@ -629,11 +629,10 @@ class LibraryController {
|
|||||||
|
|
||||||
const series = await Database.seriesModel.findByPk(req.params.seriesId)
|
const series = await Database.seriesModel.findByPk(req.params.seriesId)
|
||||||
if (!series) return res.sendStatus(404)
|
if (!series) return res.sendStatus(404)
|
||||||
const oldSeries = series.getOldSeries()
|
|
||||||
|
|
||||||
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.user)
|
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.user)
|
||||||
|
|
||||||
const seriesJson = oldSeries.toJSON()
|
const seriesJson = series.toOldJSON()
|
||||||
if (include.includes('progress')) {
|
if (include.includes('progress')) {
|
||||||
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.user.getMediaProgress(li.media.id)?.isFinished)
|
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.user.getMediaProgress(li.media.id)?.isFinished)
|
||||||
seriesJson.progress = {
|
seriesJson.progress = {
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class RSSFeedController {
|
|||||||
async openRSSFeedForSeries(req, res) {
|
async openRSSFeedForSeries(req, res) {
|
||||||
const options = req.body || {}
|
const options = req.body || {}
|
||||||
|
|
||||||
const series = await Database.seriesModel.getOldById(req.params.seriesId)
|
const series = await Database.seriesModel.findByPk(req.params.seriesId)
|
||||||
if (!series) return res.sendStatus(404)
|
if (!series) return res.sendStatus(404)
|
||||||
|
|
||||||
// Check request body options exist
|
// Check request body options exist
|
||||||
@@ -140,7 +140,7 @@ class RSSFeedController {
|
|||||||
return res.status(400).send('Slug already in use')
|
return res.status(400).send('Slug already in use')
|
||||||
}
|
}
|
||||||
|
|
||||||
const seriesJson = series.toJSON()
|
const seriesJson = series.toOldJSON()
|
||||||
|
|
||||||
// Get books in series that have audio tracks
|
// Get books in series that have audio tracks
|
||||||
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter((li) => li.media.numTracks)
|
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter((li) => li.media.numTracks)
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilter
|
|||||||
* @property {import('../models/User')} user
|
* @property {import('../models/User')} user
|
||||||
*
|
*
|
||||||
* @typedef {Request & RequestUserObject} RequestWithUser
|
* @typedef {Request & RequestUserObject} RequestWithUser
|
||||||
|
*
|
||||||
|
* @typedef RequestEntityObject
|
||||||
|
* @property {import('../models/Series')} series
|
||||||
|
*
|
||||||
|
* @typedef {RequestWithUser & RequestEntityObject} SeriesControllerRequest
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SeriesController {
|
class SeriesController {
|
||||||
@@ -21,7 +26,7 @@ class SeriesController {
|
|||||||
* TODO: Update mobile app to use /api/libraries/:id/series/:seriesId API route instead
|
* TODO: Update mobile app to use /api/libraries/:id/series/:seriesId API route instead
|
||||||
* Series are not library specific so we need to know what the library id is
|
* Series are not library specific so we need to know what the library id is
|
||||||
*
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {SeriesControllerRequest} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
async findOne(req, res) {
|
async findOne(req, res) {
|
||||||
@@ -30,7 +35,7 @@ class SeriesController {
|
|||||||
.map((v) => v.trim())
|
.map((v) => v.trim())
|
||||||
.filter((v) => !!v)
|
.filter((v) => !!v)
|
||||||
|
|
||||||
const seriesJson = req.series.toJSON()
|
const seriesJson = req.series.toOldJSON()
|
||||||
|
|
||||||
// Add progress map with isFinished flag
|
// Add progress map with isFinished flag
|
||||||
if (include.includes('progress')) {
|
if (include.includes('progress')) {
|
||||||
@@ -54,17 +59,28 @@ class SeriesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TODO: Currently unused in the client, should check for duplicate name
|
||||||
*
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {SeriesControllerRequest} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
async update(req, res) {
|
async update(req, res) {
|
||||||
const hasUpdated = req.series.update(req.body)
|
const keysToUpdate = ['name', 'description']
|
||||||
if (hasUpdated) {
|
const payload = {}
|
||||||
await Database.updateSeries(req.series)
|
for (const key of keysToUpdate) {
|
||||||
SocketAuthority.emitter('series_updated', req.series.toJSON())
|
if (req.body[key] !== undefined && typeof req.body[key] === 'string') {
|
||||||
|
payload[key] = req.body[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.json(req.series.toJSON())
|
if (!Object.keys(payload).length) {
|
||||||
|
return res.status(400).send('No valid fields to update')
|
||||||
|
}
|
||||||
|
req.series.set(payload)
|
||||||
|
if (req.series.changed()) {
|
||||||
|
await req.series.save()
|
||||||
|
SocketAuthority.emitter('series_updated', req.series.toOldJSON())
|
||||||
|
}
|
||||||
|
res.json(req.series.toOldJSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +90,7 @@ class SeriesController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async middleware(req, res, next) {
|
async middleware(req, res, next) {
|
||||||
const series = await Database.seriesModel.getOldById(req.params.id)
|
const series = await Database.seriesModel.findByPk(req.params.id)
|
||||||
if (!series) return res.sendStatus(404)
|
if (!series) return res.sendStatus(404)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -205,9 +205,12 @@ class UserController {
|
|||||||
async update(req, res) {
|
async update(req, res) {
|
||||||
const user = req.reqUser
|
const user = req.reqUser
|
||||||
|
|
||||||
if (user.type === 'root' && !req.user.isRoot) {
|
if (user.isRoot && !req.user.isRoot) {
|
||||||
Logger.error(`[UserController] Admin user "${req.user.username}" attempted to update root user`)
|
Logger.error(`[UserController] Admin user "${req.user.username}" attempted to update root user`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
|
} else if (user.isRoot) {
|
||||||
|
// Root user cannot update type
|
||||||
|
delete req.body.type
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatePayload = req.body
|
const updatePayload = req.body
|
||||||
@@ -270,8 +273,10 @@ class UserController {
|
|||||||
const permissions = {
|
const permissions = {
|
||||||
...user.permissions
|
...user.permissions
|
||||||
}
|
}
|
||||||
|
const defaultPermissions = Database.userModel.getDefaultPermissionsForUserType(updatePayload.type || user.type || 'user')
|
||||||
for (const key in updatePayload.permissions) {
|
for (const key in updatePayload.permissions) {
|
||||||
if (permissions[key] !== undefined) {
|
// Check that the key is a valid permission key or is included in the default permissions
|
||||||
|
if (permissions[key] !== undefined || defaultPermissions[key] !== undefined) {
|
||||||
if (typeof updatePayload.permissions[key] !== 'boolean') {
|
if (typeof updatePayload.permissions[key] !== 'boolean') {
|
||||||
Logger.warn(`[UserController] update: Invalid permission value for key ${key}. Should be boolean`)
|
Logger.warn(`[UserController] update: Invalid permission value for key ${key}. Should be boolean`)
|
||||||
} else if (permissions[key] !== updatePayload.permissions[key]) {
|
} else if (permissions[key] !== updatePayload.permissions[key]) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class RssFeedManager {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else if (feedObj.entityType === 'series') {
|
} else if (feedObj.entityType === 'series') {
|
||||||
const series = await Database.seriesModel.getOldById(feedObj.entityId)
|
const series = await Database.seriesModel.findByPk(feedObj.entityId)
|
||||||
if (!series) {
|
if (!series) {
|
||||||
Logger.error(`[RssFeedManager] Removing feed "${feedObj.id}". Series "${feedObj.entityId}" not found`)
|
Logger.error(`[RssFeedManager] Removing feed "${feedObj.id}". Series "${feedObj.entityId}" not found`)
|
||||||
return false
|
return false
|
||||||
@@ -133,9 +133,9 @@ class RssFeedManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (feed.entityType === 'series') {
|
} else if (feed.entityType === 'series') {
|
||||||
const series = await Database.seriesModel.getOldById(feed.entityId)
|
const series = await Database.seriesModel.findByPk(feed.entityId)
|
||||||
if (series) {
|
if (series) {
|
||||||
const seriesJson = series.toJSON()
|
const seriesJson = series.toOldJSON()
|
||||||
|
|
||||||
// Get books in series that have audio tracks
|
// Get books in series that have audio tracks
|
||||||
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter((li) => li.media.numTracks)
|
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter((li) => li.media.numTracks)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { DataTypes, Model, where, fn, col } = require('sequelize')
|
const { DataTypes, Model, where, fn, col } = require('sequelize')
|
||||||
|
const parseNameString = require('../utils/parsers/parseNameString')
|
||||||
|
|
||||||
class Author extends Model {
|
class Author extends Model {
|
||||||
constructor(values, options) {
|
constructor(values, options) {
|
||||||
@@ -24,6 +25,16 @@ class Author extends Model {
|
|||||||
this.createdAt
|
this.createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static getLastFirst(name) {
|
||||||
|
if (!name) return null
|
||||||
|
return parseNameString.nameToLastFirst(name)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if author exists
|
* Check if author exists
|
||||||
* @param {string} authorId
|
* @param {string} authorId
|
||||||
|
|||||||
+32
-79
@@ -1,6 +1,6 @@
|
|||||||
const { DataTypes, Model, where, fn, col } = require('sequelize')
|
const { DataTypes, Model, where, fn, col } = require('sequelize')
|
||||||
|
|
||||||
const oldSeries = require('../objects/entities/Series')
|
const { getTitlePrefixAtEnd } = require('../utils/index')
|
||||||
|
|
||||||
class Series extends Model {
|
class Series extends Model {
|
||||||
constructor(values, options) {
|
constructor(values, options) {
|
||||||
@@ -22,70 +22,6 @@ class Series extends Model {
|
|||||||
this.updatedAt
|
this.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getAllOldSeries() {
|
|
||||||
const series = await this.findAll()
|
|
||||||
return series.map((se) => se.getOldSeries())
|
|
||||||
}
|
|
||||||
|
|
||||||
getOldSeries() {
|
|
||||||
return new oldSeries({
|
|
||||||
id: this.id,
|
|
||||||
name: this.name,
|
|
||||||
description: this.description,
|
|
||||||
libraryId: this.libraryId,
|
|
||||||
addedAt: this.createdAt.valueOf(),
|
|
||||||
updatedAt: this.updatedAt.valueOf()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static updateFromOld(oldSeries) {
|
|
||||||
const series = this.getFromOld(oldSeries)
|
|
||||||
return this.update(series, {
|
|
||||||
where: {
|
|
||||||
id: series.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static createFromOld(oldSeries) {
|
|
||||||
const series = this.getFromOld(oldSeries)
|
|
||||||
return this.create(series)
|
|
||||||
}
|
|
||||||
|
|
||||||
static createBulkFromOld(oldSeriesObjs) {
|
|
||||||
const series = oldSeriesObjs.map(this.getFromOld)
|
|
||||||
return this.bulkCreate(series)
|
|
||||||
}
|
|
||||||
|
|
||||||
static getFromOld(oldSeries) {
|
|
||||||
return {
|
|
||||||
id: oldSeries.id,
|
|
||||||
name: oldSeries.name,
|
|
||||||
nameIgnorePrefix: oldSeries.nameIgnorePrefix,
|
|
||||||
description: oldSeries.description,
|
|
||||||
libraryId: oldSeries.libraryId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static removeById(seriesId) {
|
|
||||||
return this.destroy({
|
|
||||||
where: {
|
|
||||||
id: seriesId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get oldSeries by id
|
|
||||||
* @param {string} seriesId
|
|
||||||
* @returns {Promise<oldSeries>}
|
|
||||||
*/
|
|
||||||
static async getOldById(seriesId) {
|
|
||||||
const series = await this.findByPk(seriesId)
|
|
||||||
if (!series) return null
|
|
||||||
return series.getOldSeries()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if series exists
|
* Check if series exists
|
||||||
* @param {string} seriesId
|
* @param {string} seriesId
|
||||||
@@ -96,24 +32,21 @@ class Series extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old series by name and libraryId. name case insensitive
|
* Get series by name and libraryId. name case insensitive
|
||||||
*
|
*
|
||||||
* @param {string} seriesName
|
* @param {string} seriesName
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<oldSeries>}
|
* @returns {Promise<Series>}
|
||||||
*/
|
*/
|
||||||
static async getOldByNameAndLibrary(seriesName, libraryId) {
|
static async getByNameAndLibrary(seriesName, libraryId) {
|
||||||
const series = (
|
return this.findOne({
|
||||||
await this.findOne({
|
where: [
|
||||||
where: [
|
where(fn('lower', col('name')), seriesName.toLowerCase()),
|
||||||
where(fn('lower', col('name')), seriesName.toLowerCase()),
|
{
|
||||||
{
|
libraryId
|
||||||
libraryId
|
}
|
||||||
}
|
]
|
||||||
]
|
})
|
||||||
})
|
|
||||||
)?.getOldSeries()
|
|
||||||
return series
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,6 +96,26 @@ class Series extends Model {
|
|||||||
})
|
})
|
||||||
Series.belongsTo(library)
|
Series.belongsTo(library)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toOldJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
nameIgnorePrefix: getTitlePrefixAtEnd(this.name),
|
||||||
|
description: this.description,
|
||||||
|
addedAt: this.createdAt.valueOf(),
|
||||||
|
updatedAt: this.updatedAt.valueOf(),
|
||||||
|
libraryId: this.libraryId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSONMinimal(sequence) {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
sequence
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Series
|
module.exports = Series
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ class User extends Model {
|
|||||||
accessAllLibraries: true,
|
accessAllLibraries: true,
|
||||||
accessAllTags: true,
|
accessAllTags: true,
|
||||||
accessExplicitContent: true,
|
accessExplicitContent: true,
|
||||||
|
selectedTagsNotAccessible: false,
|
||||||
librariesAccessible: [],
|
librariesAccessible: [],
|
||||||
itemTagsSelected: []
|
itemTagsSelected: []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
const uuidv4 = require("uuid").v4
|
|
||||||
const { getTitleIgnorePrefix, getTitlePrefixAtEnd } = require('../../utils/index')
|
|
||||||
|
|
||||||
class Series {
|
|
||||||
constructor(series) {
|
|
||||||
this.id = null
|
|
||||||
this.name = null
|
|
||||||
this.description = null
|
|
||||||
this.addedAt = null
|
|
||||||
this.updatedAt = null
|
|
||||||
this.libraryId = null
|
|
||||||
|
|
||||||
if (series) {
|
|
||||||
this.construct(series)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
construct(series) {
|
|
||||||
this.id = series.id
|
|
||||||
this.name = series.name
|
|
||||||
this.description = series.description || null
|
|
||||||
this.addedAt = series.addedAt
|
|
||||||
this.updatedAt = series.updatedAt
|
|
||||||
this.libraryId = series.libraryId
|
|
||||||
}
|
|
||||||
|
|
||||||
get nameIgnorePrefix() {
|
|
||||||
if (!this.name) return ''
|
|
||||||
return getTitleIgnorePrefix(this.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
name: this.name,
|
|
||||||
nameIgnorePrefix: getTitlePrefixAtEnd(this.name),
|
|
||||||
description: this.description,
|
|
||||||
addedAt: this.addedAt,
|
|
||||||
updatedAt: this.updatedAt,
|
|
||||||
libraryId: this.libraryId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSONMinimal(sequence) {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
name: this.name,
|
|
||||||
sequence
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setData(data, libraryId) {
|
|
||||||
this.id = uuidv4()
|
|
||||||
this.name = data.name
|
|
||||||
this.description = data.description || null
|
|
||||||
this.addedAt = Date.now()
|
|
||||||
this.updatedAt = Date.now()
|
|
||||||
this.libraryId = libraryId
|
|
||||||
}
|
|
||||||
|
|
||||||
update(series) {
|
|
||||||
if (!series) return false
|
|
||||||
const keysToUpdate = ['name', 'description']
|
|
||||||
let hasUpdated = false
|
|
||||||
for (const key of keysToUpdate) {
|
|
||||||
if (series[key] !== undefined && series[key] !== this[key]) {
|
|
||||||
this[key] = series[key]
|
|
||||||
hasUpdated = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasUpdated
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNameEquals(name) {
|
|
||||||
if (!name || !this.name) return false
|
|
||||||
return this.name.toLowerCase() == name.toLowerCase().trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = Series
|
|
||||||
@@ -33,7 +33,7 @@ const CustomMetadataProviderController = require('../controllers/CustomMetadataP
|
|||||||
const MiscController = require('../controllers/MiscController')
|
const MiscController = require('../controllers/MiscController')
|
||||||
const ShareController = require('../controllers/ShareController')
|
const ShareController = require('../controllers/ShareController')
|
||||||
|
|
||||||
const Series = require('../objects/entities/Series')
|
const { getTitleIgnorePrefix } = require('../utils/index')
|
||||||
|
|
||||||
class ApiRouter {
|
class ApiRouter {
|
||||||
constructor(Server) {
|
constructor(Server) {
|
||||||
@@ -524,13 +524,15 @@ class ApiRouter {
|
|||||||
async removeEmptySeries(series) {
|
async removeEmptySeries(series) {
|
||||||
await this.rssFeedManager.closeFeedForEntityId(series.id)
|
await this.rssFeedManager.closeFeedForEntityId(series.id)
|
||||||
Logger.info(`[ApiRouter] Series "${series.name}" is now empty. Removing series`)
|
Logger.info(`[ApiRouter] Series "${series.name}" is now empty. Removing series`)
|
||||||
await Database.removeSeries(series.id)
|
|
||||||
// Remove series from library filter data
|
// Remove series from library filter data
|
||||||
Database.removeSeriesFromFilterData(series.libraryId, series.id)
|
Database.removeSeriesFromFilterData(series.libraryId, series.id)
|
||||||
SocketAuthority.emitter('series_removed', {
|
SocketAuthority.emitter('series_removed', {
|
||||||
id: series.id,
|
id: series.id,
|
||||||
libraryId: series.libraryId
|
libraryId: series.libraryId
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await series.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserListeningSessionsHelper(userId) {
|
async getUserListeningSessionsHelper(userId) {
|
||||||
@@ -619,6 +621,7 @@ class ApiRouter {
|
|||||||
if (!author) {
|
if (!author) {
|
||||||
author = await Database.authorModel.create({
|
author = await Database.authorModel.create({
|
||||||
name: authorName,
|
name: authorName,
|
||||||
|
lastFirst: Database.authorModel.getLastFirst(authorName),
|
||||||
libraryId
|
libraryId
|
||||||
})
|
})
|
||||||
Logger.debug(`[ApiRouter] Creating new author "${author.name}"`)
|
Logger.debug(`[ApiRouter] Creating new author "${author.name}"`)
|
||||||
@@ -663,11 +666,14 @@ class ApiRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mediaMetadata.series[i].id) {
|
if (!mediaMetadata.series[i].id) {
|
||||||
let seriesItem = await Database.seriesModel.getOldByNameAndLibrary(seriesName, libraryId)
|
let seriesItem = await Database.seriesModel.getByNameAndLibrary(seriesName, libraryId)
|
||||||
if (!seriesItem) {
|
if (!seriesItem) {
|
||||||
seriesItem = new Series()
|
seriesItem = await Database.seriesModel.create({
|
||||||
seriesItem.setData(mediaMetadata.series[i], libraryId)
|
name: seriesName,
|
||||||
Logger.debug(`[ApiRouter] Created new series "${seriesItem.name}"`)
|
nameIgnorePrefix: getTitleIgnorePrefix(seriesName),
|
||||||
|
libraryId
|
||||||
|
})
|
||||||
|
Logger.debug(`[ApiRouter] Creating new series "${seriesItem.name}"`)
|
||||||
newSeries.push(seriesItem)
|
newSeries.push(seriesItem)
|
||||||
// Update filter data
|
// Update filter data
|
||||||
Database.addSeriesToFilterData(libraryId, seriesItem.name, seriesItem.id)
|
Database.addSeriesToFilterData(libraryId, seriesItem.name, seriesItem.id)
|
||||||
@@ -680,10 +686,9 @@ class ApiRouter {
|
|||||||
// Remove series without an id
|
// Remove series without an id
|
||||||
mediaMetadata.series = mediaMetadata.series.filter((se) => se.id)
|
mediaMetadata.series = mediaMetadata.series.filter((se) => se.id)
|
||||||
if (newSeries.length) {
|
if (newSeries.length) {
|
||||||
await Database.createBulkSeries(newSeries)
|
|
||||||
SocketAuthority.emitter(
|
SocketAuthority.emitter(
|
||||||
'multiple_series_added',
|
'multiple_series_added',
|
||||||
newSeries.map((se) => se.toJSON())
|
newSeries.map((se) => se.toOldJSON())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+106
-98
@@ -1,4 +1,4 @@
|
|||||||
const uuidv4 = require("uuid").v4
|
const uuidv4 = require('uuid').v4
|
||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
const sequelize = require('sequelize')
|
const sequelize = require('sequelize')
|
||||||
const { LogLevel } = require('../utils/constants')
|
const { LogLevel } = require('../utils/constants')
|
||||||
@@ -13,14 +13,14 @@ const AudioFile = require('../objects/files/AudioFile')
|
|||||||
const CoverManager = require('../managers/CoverManager')
|
const CoverManager = require('../managers/CoverManager')
|
||||||
const LibraryFile = require('../objects/files/LibraryFile')
|
const LibraryFile = require('../objects/files/LibraryFile')
|
||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const fsExtra = require("../libs/fsExtra")
|
const fsExtra = require('../libs/fsExtra')
|
||||||
const BookFinder = require('../finders/BookFinder')
|
const BookFinder = require('../finders/BookFinder')
|
||||||
|
|
||||||
const LibraryScan = require("./LibraryScan")
|
const LibraryScan = require('./LibraryScan')
|
||||||
const OpfFileScanner = require('./OpfFileScanner')
|
const OpfFileScanner = require('./OpfFileScanner')
|
||||||
const NfoFileScanner = require('./NfoFileScanner')
|
const NfoFileScanner = require('./NfoFileScanner')
|
||||||
const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
|
const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
|
||||||
const EBookFile = require("../objects/files/EBookFile")
|
const EBookFile = require('../objects/files/EBookFile')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata for books pulled from files
|
* Metadata for books pulled from files
|
||||||
@@ -46,7 +46,7 @@ const EBookFile = require("../objects/files/EBookFile")
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class BookScanner {
|
class BookScanner {
|
||||||
constructor() { }
|
constructor() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import('../models/LibraryItem')} existingLibraryItem
|
* @param {import('../models/LibraryItem')} existingLibraryItem
|
||||||
@@ -81,19 +81,23 @@ class BookScanner {
|
|||||||
let hasMediaChanges = libraryItemData.hasAudioFileChanges || libraryItemData.audioLibraryFiles.length !== media.audioFiles.length
|
let hasMediaChanges = libraryItemData.hasAudioFileChanges || libraryItemData.audioLibraryFiles.length !== media.audioFiles.length
|
||||||
if (hasMediaChanges) {
|
if (hasMediaChanges) {
|
||||||
// Filter out audio files that were removed
|
// Filter out audio files that were removed
|
||||||
media.audioFiles = media.audioFiles.filter(af => !libraryItemData.checkAudioFileRemoved(af))
|
media.audioFiles = media.audioFiles.filter((af) => !libraryItemData.checkAudioFileRemoved(af))
|
||||||
|
|
||||||
// Update audio files that were modified
|
// Update audio files that were modified
|
||||||
if (libraryItemData.audioLibraryFilesModified.length) {
|
if (libraryItemData.audioLibraryFilesModified.length) {
|
||||||
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified.map(lf => lf.new))
|
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(
|
||||||
|
existingLibraryItem.mediaType,
|
||||||
|
libraryItemData,
|
||||||
|
libraryItemData.audioLibraryFilesModified.map((lf) => lf.new)
|
||||||
|
)
|
||||||
media.audioFiles = media.audioFiles.map((audioFileObj) => {
|
media.audioFiles = media.audioFiles.map((audioFileObj) => {
|
||||||
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === audioFileObj.metadata.path)
|
let matchedScannedAudioFile = scannedAudioFiles.find((saf) => saf.metadata.path === audioFileObj.metadata.path)
|
||||||
if (!matchedScannedAudioFile) {
|
if (!matchedScannedAudioFile) {
|
||||||
matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.ino === audioFileObj.ino)
|
matchedScannedAudioFile = scannedAudioFiles.find((saf) => saf.ino === audioFileObj.ino)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchedScannedAudioFile) {
|
if (matchedScannedAudioFile) {
|
||||||
scannedAudioFiles = scannedAudioFiles.filter(saf => saf !== matchedScannedAudioFile)
|
scannedAudioFiles = scannedAudioFiles.filter((saf) => saf !== matchedScannedAudioFile)
|
||||||
const audioFile = new AudioFile(audioFileObj)
|
const audioFile = new AudioFile(audioFileObj)
|
||||||
audioFile.updateFromScan(matchedScannedAudioFile)
|
audioFile.updateFromScan(matchedScannedAudioFile)
|
||||||
return audioFile.toJSON()
|
return audioFile.toJSON()
|
||||||
@@ -115,7 +119,7 @@ class BookScanner {
|
|||||||
// Add audio library files that are not already set on the book (safety check)
|
// Add audio library files that are not already set on the book (safety check)
|
||||||
let audioLibraryFilesToAdd = []
|
let audioLibraryFilesToAdd = []
|
||||||
for (const audioLibraryFile of libraryItemData.audioLibraryFiles) {
|
for (const audioLibraryFile of libraryItemData.audioLibraryFiles) {
|
||||||
if (!media.audioFiles.some(af => af.ino === audioLibraryFile.ino)) {
|
if (!media.audioFiles.some((af) => af.ino === audioLibraryFile.ino)) {
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Existing audio library file "${audioLibraryFile.metadata.relPath}" was not set on book "${media.title}" so setting it now`)
|
libraryScan.addLog(LogLevel.DEBUG, `Existing audio library file "${audioLibraryFile.metadata.relPath}" was not set on book "${media.title}" so setting it now`)
|
||||||
|
|
||||||
audioLibraryFilesToAdd.push(audioLibraryFile)
|
audioLibraryFilesToAdd.push(audioLibraryFile)
|
||||||
@@ -139,14 +143,14 @@ class BookScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if cover was removed
|
// Check if cover was removed
|
||||||
if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some(lf => lf.metadata.path === media.coverPath) && !(await fsExtra.pathExists(media.coverPath))) {
|
if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some((lf) => lf.metadata.path === media.coverPath) && !(await fsExtra.pathExists(media.coverPath))) {
|
||||||
media.coverPath = null
|
media.coverPath = null
|
||||||
hasMediaChanges = true
|
hasMediaChanges = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cover if it was modified
|
// Update cover if it was modified
|
||||||
if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) {
|
if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) {
|
||||||
let coverMatch = libraryItemData.imageLibraryFilesModified.find(iFile => iFile.old.metadata.path === media.coverPath)
|
let coverMatch = libraryItemData.imageLibraryFilesModified.find((iFile) => iFile.old.metadata.path === media.coverPath)
|
||||||
if (coverMatch) {
|
if (coverMatch) {
|
||||||
const coverPath = coverMatch.new.metadata.path
|
const coverPath = coverMatch.new.metadata.path
|
||||||
if (coverPath !== media.coverPath) {
|
if (coverPath !== media.coverPath) {
|
||||||
@@ -161,7 +165,7 @@ class BookScanner {
|
|||||||
// Check if cover is not set and image files were found
|
// Check if cover is not set and image files were found
|
||||||
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
|
||||||
// Prefer using a cover image with the name "cover" otherwise use the first image
|
// Prefer using a cover image with the name "cover" otherwise use the first image
|
||||||
const coverMatch = libraryItemData.imageLibraryFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
const coverMatch = libraryItemData.imageLibraryFiles.find((iFile) => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
||||||
media.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
|
media.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
|
||||||
hasMediaChanges = true
|
hasMediaChanges = true
|
||||||
}
|
}
|
||||||
@@ -174,7 +178,7 @@ class BookScanner {
|
|||||||
|
|
||||||
// Update ebook if it was modified
|
// Update ebook if it was modified
|
||||||
if (media.ebookFile && libraryItemData.ebookLibraryFilesModified.length) {
|
if (media.ebookFile && libraryItemData.ebookLibraryFilesModified.length) {
|
||||||
let ebookMatch = libraryItemData.ebookLibraryFilesModified.find(eFile => eFile.old.metadata.path === media.ebookFile.metadata.path)
|
let ebookMatch = libraryItemData.ebookLibraryFilesModified.find((eFile) => eFile.old.metadata.path === media.ebookFile.metadata.path)
|
||||||
if (ebookMatch) {
|
if (ebookMatch) {
|
||||||
const ebookFile = new EBookFile(ebookMatch.new)
|
const ebookFile = new EBookFile(ebookMatch.new)
|
||||||
ebookFile.ebookFormat = ebookFile.metadata.ext.slice(1).toLowerCase()
|
ebookFile.ebookFormat = ebookFile.metadata.ext.slice(1).toLowerCase()
|
||||||
@@ -188,7 +192,7 @@ class BookScanner {
|
|||||||
// Check if ebook is not set and ebooks were found
|
// Check if ebook is not set and ebooks were found
|
||||||
if (!media.ebookFile && !librarySettings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
|
if (!media.ebookFile && !librarySettings.audiobooksOnly && libraryItemData.ebookLibraryFiles.length) {
|
||||||
// Prefer to use an epub ebook then fallback to the first ebook found
|
// Prefer to use an epub ebook then fallback to the first ebook found
|
||||||
let ebookLibraryFile = libraryItemData.ebookLibraryFiles.find(lf => lf.metadata.ext.slice(1).toLowerCase() === 'epub')
|
let ebookLibraryFile = libraryItemData.ebookLibraryFiles.find((lf) => lf.metadata.ext.slice(1).toLowerCase() === 'epub')
|
||||||
if (!ebookLibraryFile) ebookLibraryFile = libraryItemData.ebookLibraryFiles[0]
|
if (!ebookLibraryFile) ebookLibraryFile = libraryItemData.ebookLibraryFiles[0]
|
||||||
ebookLibraryFile = ebookLibraryFile.toJSON()
|
ebookLibraryFile = ebookLibraryFile.toJSON()
|
||||||
// Ebook file is the same as library file except for additional `ebookFormat`
|
// Ebook file is the same as library file except for additional `ebookFormat`
|
||||||
@@ -213,7 +217,7 @@ class BookScanner {
|
|||||||
if (key === 'authors') {
|
if (key === 'authors') {
|
||||||
// Check for authors added
|
// Check for authors added
|
||||||
for (const authorName of bookMetadata.authors) {
|
for (const authorName of bookMetadata.authors) {
|
||||||
if (!media.authors.some(au => au.name === authorName)) {
|
if (!media.authors.some((au) => au.name === authorName)) {
|
||||||
const existingAuthorId = await Database.getAuthorIdByName(libraryItemData.libraryId, authorName)
|
const existingAuthorId = await Database.getAuthorIdByName(libraryItemData.libraryId, authorName)
|
||||||
if (existingAuthorId) {
|
if (existingAuthorId) {
|
||||||
await Database.bookAuthorModel.create({
|
await Database.bookAuthorModel.create({
|
||||||
@@ -225,7 +229,7 @@ class BookScanner {
|
|||||||
} else {
|
} else {
|
||||||
const newAuthor = await Database.authorModel.create({
|
const newAuthor = await Database.authorModel.create({
|
||||||
name: authorName,
|
name: authorName,
|
||||||
lastFirst: parseNameString.nameToLastFirst(authorName),
|
lastFirst: Database.authorModel.getLastFirst(authorName),
|
||||||
libraryId: libraryItemData.libraryId
|
libraryId: libraryItemData.libraryId
|
||||||
})
|
})
|
||||||
await media.addAuthor(newAuthor)
|
await media.addAuthor(newAuthor)
|
||||||
@@ -247,7 +251,7 @@ class BookScanner {
|
|||||||
} else if (key === 'series') {
|
} else if (key === 'series') {
|
||||||
// Check for series added
|
// Check for series added
|
||||||
for (const seriesObj of bookMetadata.series) {
|
for (const seriesObj of bookMetadata.series) {
|
||||||
const existingBookSeries = media.series.find(se => se.name === seriesObj.name)
|
const existingBookSeries = media.series.find((se) => se.name === seriesObj.name)
|
||||||
if (!existingBookSeries) {
|
if (!existingBookSeries) {
|
||||||
const existingSeriesId = await Database.getSeriesIdByName(libraryItemData.libraryId, seriesObj.name)
|
const existingSeriesId = await Database.getSeriesIdByName(libraryItemData.libraryId, seriesObj.name)
|
||||||
if (existingSeriesId) {
|
if (existingSeriesId) {
|
||||||
@@ -278,7 +282,7 @@ class BookScanner {
|
|||||||
}
|
}
|
||||||
// Check for series removed
|
// Check for series removed
|
||||||
for (const series of media.series) {
|
for (const series of media.series) {
|
||||||
if (!bookMetadata.series.some(se => se.name === series.name)) {
|
if (!bookMetadata.series.some((se) => se.name === series.name)) {
|
||||||
await series.bookSeries.destroy()
|
await series.bookSeries.destroy()
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Updating book "${bookMetadata.title}" removed series "${series.name}"`)
|
libraryScan.addLog(LogLevel.DEBUG, `Updating book "${bookMetadata.title}" removed series "${series.name}"`)
|
||||||
seriesUpdated = true
|
seriesUpdated = true
|
||||||
@@ -287,21 +291,21 @@ class BookScanner {
|
|||||||
}
|
}
|
||||||
} else if (key === 'genres') {
|
} else if (key === 'genres') {
|
||||||
const existingGenres = media.genres || []
|
const existingGenres = media.genres || []
|
||||||
if (bookMetadata.genres.some(g => !existingGenres.includes(g)) || existingGenres.some(g => !bookMetadata.genres.includes(g))) {
|
if (bookMetadata.genres.some((g) => !existingGenres.includes(g)) || existingGenres.some((g) => !bookMetadata.genres.includes(g))) {
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Updating book genres "${existingGenres.join(',')}" => "${bookMetadata.genres.join(',')}" for book "${bookMetadata.title}"`)
|
libraryScan.addLog(LogLevel.DEBUG, `Updating book genres "${existingGenres.join(',')}" => "${bookMetadata.genres.join(',')}" for book "${bookMetadata.title}"`)
|
||||||
media.genres = bookMetadata.genres
|
media.genres = bookMetadata.genres
|
||||||
hasMediaChanges = true
|
hasMediaChanges = true
|
||||||
}
|
}
|
||||||
} else if (key === 'tags') {
|
} else if (key === 'tags') {
|
||||||
const existingTags = media.tags || []
|
const existingTags = media.tags || []
|
||||||
if (bookMetadata.tags.some(t => !existingTags.includes(t)) || existingTags.some(t => !bookMetadata.tags.includes(t))) {
|
if (bookMetadata.tags.some((t) => !existingTags.includes(t)) || existingTags.some((t) => !bookMetadata.tags.includes(t))) {
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Updating book tags "${existingTags.join(',')}" => "${bookMetadata.tags.join(',')}" for book "${bookMetadata.title}"`)
|
libraryScan.addLog(LogLevel.DEBUG, `Updating book tags "${existingTags.join(',')}" => "${bookMetadata.tags.join(',')}" for book "${bookMetadata.title}"`)
|
||||||
media.tags = bookMetadata.tags
|
media.tags = bookMetadata.tags
|
||||||
hasMediaChanges = true
|
hasMediaChanges = true
|
||||||
}
|
}
|
||||||
} else if (key === 'narrators') {
|
} else if (key === 'narrators') {
|
||||||
const existingNarrators = media.narrators || []
|
const existingNarrators = media.narrators || []
|
||||||
if (bookMetadata.narrators.some(t => !existingNarrators.includes(t)) || existingNarrators.some(t => !bookMetadata.narrators.includes(t))) {
|
if (bookMetadata.narrators.some((t) => !existingNarrators.includes(t)) || existingNarrators.some((t) => !bookMetadata.narrators.includes(t))) {
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Updating book narrators "${existingNarrators.join(',')}" => "${bookMetadata.narrators.join(',')}" for book "${bookMetadata.title}"`)
|
libraryScan.addLog(LogLevel.DEBUG, `Updating book narrators "${existingNarrators.join(',')}" => "${bookMetadata.narrators.join(',')}" for book "${bookMetadata.title}"`)
|
||||||
media.narrators = bookMetadata.narrators
|
media.narrators = bookMetadata.narrators
|
||||||
hasMediaChanges = true
|
hasMediaChanges = true
|
||||||
@@ -333,17 +337,13 @@ class BookScanner {
|
|||||||
if (authorsUpdated) {
|
if (authorsUpdated) {
|
||||||
media.authors = await media.getAuthors({
|
media.authors = await media.getAuthors({
|
||||||
joinTableAttributes: ['createdAt'],
|
joinTableAttributes: ['createdAt'],
|
||||||
order: [
|
order: [sequelize.literal(`bookAuthor.createdAt ASC`)]
|
||||||
sequelize.literal(`bookAuthor.createdAt ASC`)
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (seriesUpdated) {
|
if (seriesUpdated) {
|
||||||
media.series = await media.getSeries({
|
media.series = await media.getSeries({
|
||||||
joinTableAttributes: ['sequence', 'createdAt'],
|
joinTableAttributes: ['sequence', 'createdAt'],
|
||||||
order: [
|
order: [sequelize.literal(`bookSeries.createdAt ASC`)]
|
||||||
sequelize.literal(`bookSeries.createdAt ASC`)
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +367,10 @@ class BookScanner {
|
|||||||
|
|
||||||
// If no cover then search for cover if enabled in server settings
|
// If no cover then search for cover if enabled in server settings
|
||||||
if (!media.coverPath && Database.serverSettings.scannerFindCovers) {
|
if (!media.coverPath && Database.serverSettings.scannerFindCovers) {
|
||||||
const authorName = media.authors.map(au => au.name).filter(au => au).join(', ')
|
const authorName = media.authors
|
||||||
|
.map((au) => au.name)
|
||||||
|
.filter((au) => au)
|
||||||
|
.join(', ')
|
||||||
const coverPath = await this.searchForCover(existingLibraryItem.id, libraryItemDir, media.title, authorName, libraryScan)
|
const coverPath = await this.searchForCover(existingLibraryItem.id, libraryItemDir, media.title, authorName, libraryScan)
|
||||||
if (coverPath) {
|
if (coverPath) {
|
||||||
media.coverPath = coverPath
|
media.coverPath = coverPath
|
||||||
@@ -440,7 +443,7 @@ class BookScanner {
|
|||||||
scannedAudioFiles = AudioFileScanner.runSmartTrackOrder(libraryItemData.relPath, scannedAudioFiles)
|
scannedAudioFiles = AudioFileScanner.runSmartTrackOrder(libraryItemData.relPath, scannedAudioFiles)
|
||||||
|
|
||||||
// Find ebook file (prefer epub)
|
// Find ebook file (prefer epub)
|
||||||
let ebookLibraryFile = librarySettings.audiobooksOnly ? null : libraryItemData.ebookLibraryFiles.find(lf => lf.metadata.ext.slice(1).toLowerCase() === 'epub') || libraryItemData.ebookLibraryFiles[0]
|
let ebookLibraryFile = librarySettings.audiobooksOnly ? null : libraryItemData.ebookLibraryFiles.find((lf) => lf.metadata.ext.slice(1).toLowerCase() === 'epub') || libraryItemData.ebookLibraryFiles[0]
|
||||||
|
|
||||||
// Do not add library items that have no valid audio files and no ebook file
|
// Do not add library items that have no valid audio files and no ebook file
|
||||||
if (!ebookLibraryFile && !scannedAudioFiles.length) {
|
if (!ebookLibraryFile && !scannedAudioFiles.length) {
|
||||||
@@ -460,7 +463,7 @@ class BookScanner {
|
|||||||
bookMetadata.abridged = !!bookMetadata.abridged // Ensure boolean
|
bookMetadata.abridged = !!bookMetadata.abridged // Ensure boolean
|
||||||
|
|
||||||
let duration = 0
|
let duration = 0
|
||||||
scannedAudioFiles.forEach((af) => duration += (!isNaN(af.duration) ? Number(af.duration) : 0))
|
scannedAudioFiles.forEach((af) => (duration += !isNaN(af.duration) ? Number(af.duration) : 0))
|
||||||
const bookObject = {
|
const bookObject = {
|
||||||
...bookMetadata,
|
...bookMetadata,
|
||||||
audioFiles: scannedAudioFiles,
|
audioFiles: scannedAudioFiles,
|
||||||
@@ -482,7 +485,7 @@ class BookScanner {
|
|||||||
author: {
|
author: {
|
||||||
libraryId: libraryItemData.libraryId,
|
libraryId: libraryItemData.libraryId,
|
||||||
name: authorName,
|
name: authorName,
|
||||||
lastFirst: parseNameString.nameToLastFirst(authorName)
|
lastFirst: Database.authorModel.getLastFirst(authorName)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -664,7 +667,7 @@ class BookScanner {
|
|||||||
|
|
||||||
// Set cover from library file if one is found otherwise check audiofile
|
// Set cover from library file if one is found otherwise check audiofile
|
||||||
if (libraryItemData.imageLibraryFiles.length) {
|
if (libraryItemData.imageLibraryFiles.length) {
|
||||||
const coverMatch = libraryItemData.imageLibraryFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
const coverMatch = libraryItemData.imageLibraryFiles.find((iFile) => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
|
||||||
bookMetadata.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
|
bookMetadata.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,7 +676,6 @@ class BookScanner {
|
|||||||
return bookMetadata
|
return bookMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static BookMetadataSourceHandler = class {
|
static BookMetadataSourceHandler = class {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -805,12 +807,12 @@ class BookScanner {
|
|||||||
|
|
||||||
const jsonObject = {
|
const jsonObject = {
|
||||||
tags: libraryItem.media.tags || [],
|
tags: libraryItem.media.tags || [],
|
||||||
chapters: libraryItem.media.chapters?.map(c => ({ ...c })) || [],
|
chapters: libraryItem.media.chapters?.map((c) => ({ ...c })) || [],
|
||||||
title: libraryItem.media.title,
|
title: libraryItem.media.title,
|
||||||
subtitle: libraryItem.media.subtitle,
|
subtitle: libraryItem.media.subtitle,
|
||||||
authors: libraryItem.media.authors.map(a => a.name),
|
authors: libraryItem.media.authors.map((a) => a.name),
|
||||||
narrators: libraryItem.media.narrators,
|
narrators: libraryItem.media.narrators,
|
||||||
series: libraryItem.media.series.map(se => {
|
series: libraryItem.media.series.map((se) => {
|
||||||
const sequence = se.bookSeries?.sequence || ''
|
const sequence = se.bookSeries?.sequence || ''
|
||||||
if (!sequence) return se.name
|
if (!sequence) return se.name
|
||||||
return `${se.name} #${sequence}`
|
return `${se.name} #${sequence}`
|
||||||
@@ -826,41 +828,44 @@ class BookScanner {
|
|||||||
explicit: !!libraryItem.media.explicit,
|
explicit: !!libraryItem.media.explicit,
|
||||||
abridged: !!libraryItem.media.abridged
|
abridged: !!libraryItem.media.abridged
|
||||||
}
|
}
|
||||||
return fsExtra.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2)).then(async () => {
|
return fsExtra
|
||||||
// Add metadata.json to libraryFiles array if it is new
|
.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2))
|
||||||
let metadataLibraryFile = libraryItem.libraryFiles.find(lf => lf.metadata.path === filePathToPOSIX(metadataFilePath))
|
.then(async () => {
|
||||||
if (storeMetadataWithItem) {
|
// Add metadata.json to libraryFiles array if it is new
|
||||||
if (!metadataLibraryFile) {
|
let metadataLibraryFile = libraryItem.libraryFiles.find((lf) => lf.metadata.path === filePathToPOSIX(metadataFilePath))
|
||||||
const newLibraryFile = new LibraryFile()
|
if (storeMetadataWithItem) {
|
||||||
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.json`)
|
if (!metadataLibraryFile) {
|
||||||
metadataLibraryFile = newLibraryFile.toJSON()
|
const newLibraryFile = new LibraryFile()
|
||||||
libraryItem.libraryFiles.push(metadataLibraryFile)
|
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.json`)
|
||||||
} else {
|
metadataLibraryFile = newLibraryFile.toJSON()
|
||||||
const fileTimestamps = await getFileTimestampsWithIno(metadataFilePath)
|
libraryItem.libraryFiles.push(metadataLibraryFile)
|
||||||
if (fileTimestamps) {
|
} else {
|
||||||
metadataLibraryFile.metadata.mtimeMs = fileTimestamps.mtimeMs
|
const fileTimestamps = await getFileTimestampsWithIno(metadataFilePath)
|
||||||
metadataLibraryFile.metadata.ctimeMs = fileTimestamps.ctimeMs
|
if (fileTimestamps) {
|
||||||
metadataLibraryFile.metadata.size = fileTimestamps.size
|
metadataLibraryFile.metadata.mtimeMs = fileTimestamps.mtimeMs
|
||||||
metadataLibraryFile.ino = fileTimestamps.ino
|
metadataLibraryFile.metadata.ctimeMs = fileTimestamps.ctimeMs
|
||||||
|
metadataLibraryFile.metadata.size = fileTimestamps.size
|
||||||
|
metadataLibraryFile.ino = fileTimestamps.ino
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const libraryItemDirTimestamps = await getFileTimestampsWithIno(libraryItem.path)
|
||||||
|
if (libraryItemDirTimestamps) {
|
||||||
|
libraryItem.mtime = libraryItemDirTimestamps.mtimeMs
|
||||||
|
libraryItem.ctime = libraryItemDirTimestamps.ctimeMs
|
||||||
|
let size = 0
|
||||||
|
libraryItem.libraryFiles.forEach((lf) => (size += !isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0))
|
||||||
|
libraryItem.size = size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const libraryItemDirTimestamps = await getFileTimestampsWithIno(libraryItem.path)
|
|
||||||
if (libraryItemDirTimestamps) {
|
|
||||||
libraryItem.mtime = libraryItemDirTimestamps.mtimeMs
|
|
||||||
libraryItem.ctime = libraryItemDirTimestamps.ctimeMs
|
|
||||||
let size = 0
|
|
||||||
libraryItem.libraryFiles.forEach((lf) => size += (!isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0))
|
|
||||||
libraryItem.size = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `Success saving abmetadata to "${metadataFilePath}"`)
|
libraryScan.addLog(LogLevel.DEBUG, `Success saving abmetadata to "${metadataFilePath}"`)
|
||||||
|
|
||||||
return metadataLibraryFile
|
return metadataLibraryFile
|
||||||
}).catch((error) => {
|
})
|
||||||
libraryScan.addLog(LogLevel.ERROR, `Failed to save json file at "${metadataFilePath}"`, error)
|
.catch((error) => {
|
||||||
return null
|
libraryScan.addLog(LogLevel.ERROR, `Failed to save json file at "${metadataFilePath}"`, error)
|
||||||
})
|
return null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -871,25 +876,27 @@ class BookScanner {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
async checkAuthorsRemovedFromBooks(libraryId, scanLogger) {
|
async checkAuthorsRemovedFromBooks(libraryId, scanLogger) {
|
||||||
const bookAuthorsToRemove = (await Database.authorModel.findAll({
|
const bookAuthorsToRemove = (
|
||||||
where: [
|
await Database.authorModel.findAll({
|
||||||
{
|
where: [
|
||||||
id: scanLogger.authorsRemovedFromBooks,
|
{
|
||||||
asin: {
|
id: scanLogger.authorsRemovedFromBooks,
|
||||||
[sequelize.Op.or]: [null, ""]
|
asin: {
|
||||||
|
[sequelize.Op.or]: [null, '']
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
[sequelize.Op.or]: [null, '']
|
||||||
|
},
|
||||||
|
imagePath: {
|
||||||
|
[sequelize.Op.or]: [null, '']
|
||||||
|
}
|
||||||
},
|
},
|
||||||
description: {
|
sequelize.where(sequelize.literal('(SELECT count(*) FROM bookAuthors ba WHERE ba.authorId = author.id)'), 0)
|
||||||
[sequelize.Op.or]: [null, ""]
|
],
|
||||||
},
|
attributes: ['id'],
|
||||||
imagePath: {
|
raw: true
|
||||||
[sequelize.Op.or]: [null, ""]
|
})
|
||||||
}
|
).map((au) => au.id)
|
||||||
},
|
|
||||||
sequelize.where(sequelize.literal('(SELECT count(*) FROM bookAuthors ba WHERE ba.authorId = author.id)'), 0)
|
|
||||||
],
|
|
||||||
attributes: ['id'],
|
|
||||||
raw: true
|
|
||||||
})).map(au => au.id)
|
|
||||||
if (bookAuthorsToRemove.length) {
|
if (bookAuthorsToRemove.length) {
|
||||||
await Database.authorModel.destroy({
|
await Database.authorModel.destroy({
|
||||||
where: {
|
where: {
|
||||||
@@ -912,16 +919,18 @@ class BookScanner {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
async checkSeriesRemovedFromBooks(libraryId, scanLogger) {
|
async checkSeriesRemovedFromBooks(libraryId, scanLogger) {
|
||||||
const bookSeriesToRemove = (await Database.seriesModel.findAll({
|
const bookSeriesToRemove = (
|
||||||
where: [
|
await Database.seriesModel.findAll({
|
||||||
{
|
where: [
|
||||||
id: scanLogger.seriesRemovedFromBooks
|
{
|
||||||
},
|
id: scanLogger.seriesRemovedFromBooks
|
||||||
sequelize.where(sequelize.literal('(SELECT count(*) FROM bookSeries bs WHERE bs.seriesId = series.id)'), 0)
|
},
|
||||||
],
|
sequelize.where(sequelize.literal('(SELECT count(*) FROM bookSeries bs WHERE bs.seriesId = series.id)'), 0)
|
||||||
attributes: ['id'],
|
],
|
||||||
raw: true
|
attributes: ['id'],
|
||||||
})).map(se => se.id)
|
raw: true
|
||||||
|
})
|
||||||
|
).map((se) => se.id)
|
||||||
if (bookSeriesToRemove.length) {
|
if (bookSeriesToRemove.length) {
|
||||||
await Database.seriesModel.destroy({
|
await Database.seriesModel.destroy({
|
||||||
where: {
|
where: {
|
||||||
@@ -956,7 +965,6 @@ class BookScanner {
|
|||||||
|
|
||||||
// If the first cover result fails, attempt to download the second
|
// If the first cover result fails, attempt to download the second
|
||||||
for (let i = 0; i < results.length && i < 2; i++) {
|
for (let i = 0; i < results.length && i < 2; i++) {
|
||||||
|
|
||||||
// Downloads and updates the book cover
|
// Downloads and updates the book cover
|
||||||
const result = await CoverManager.downloadCoverFromUrlNew(results[i], libraryItemId, libraryItemPath)
|
const result = await CoverManager.downloadCoverFromUrlNew(results[i], libraryItemId, libraryItemPath)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const { findMatchingEpisodesInFeed, getPodcastFeed } = require('../utils/podcast
|
|||||||
const BookFinder = require('../finders/BookFinder')
|
const BookFinder = require('../finders/BookFinder')
|
||||||
const PodcastFinder = require('../finders/PodcastFinder')
|
const PodcastFinder = require('../finders/PodcastFinder')
|
||||||
const LibraryScan = require('./LibraryScan')
|
const LibraryScan = require('./LibraryScan')
|
||||||
const Series = require('../objects/entities/Series')
|
|
||||||
const LibraryScanner = require('./LibraryScanner')
|
const LibraryScanner = require('./LibraryScanner')
|
||||||
const CoverManager = require('../managers/CoverManager')
|
const CoverManager = require('../managers/CoverManager')
|
||||||
const TaskManager = require('../managers/TaskManager')
|
const TaskManager = require('../managers/TaskManager')
|
||||||
@@ -209,6 +208,7 @@ class Scanner {
|
|||||||
if (!author) {
|
if (!author) {
|
||||||
author = await Database.authorModel.create({
|
author = await Database.authorModel.create({
|
||||||
name: authorName,
|
name: authorName,
|
||||||
|
lastFirst: Database.authorModel.getLastFirst(authorName),
|
||||||
libraryId: libraryItem.libraryId
|
libraryId: libraryItem.libraryId
|
||||||
})
|
})
|
||||||
SocketAuthority.emitter('author_added', author.toOldJSON())
|
SocketAuthority.emitter('author_added', author.toOldJSON())
|
||||||
@@ -225,14 +225,16 @@ class Scanner {
|
|||||||
if (!Array.isArray(matchData.series)) matchData.series = [{ series: matchData.series, sequence: matchData.sequence }]
|
if (!Array.isArray(matchData.series)) matchData.series = [{ series: matchData.series, sequence: matchData.sequence }]
|
||||||
const seriesPayload = []
|
const seriesPayload = []
|
||||||
for (const seriesMatchItem of matchData.series) {
|
for (const seriesMatchItem of matchData.series) {
|
||||||
let seriesItem = await Database.seriesModel.getOldByNameAndLibrary(seriesMatchItem.series, libraryItem.libraryId)
|
let seriesItem = await Database.seriesModel.getByNameAndLibrary(seriesMatchItem.series, libraryItem.libraryId)
|
||||||
if (!seriesItem) {
|
if (!seriesItem) {
|
||||||
seriesItem = new Series()
|
seriesItem = await Database.seriesModel.create({
|
||||||
seriesItem.setData({ name: seriesMatchItem.series }, libraryItem.libraryId)
|
name: seriesMatchItem.series,
|
||||||
await Database.createSeries(seriesItem)
|
nameIgnorePrefix: getTitleIgnorePrefix(seriesMatchItem.series),
|
||||||
|
libraryId
|
||||||
|
})
|
||||||
// Update filter data
|
// Update filter data
|
||||||
Database.addSeriesToFilterData(libraryItem.libraryId, seriesItem.name, seriesItem.id)
|
Database.addSeriesToFilterData(libraryItem.libraryId, seriesItem.name, seriesItem.id)
|
||||||
SocketAuthority.emitter('series_added', seriesItem.toJSON())
|
SocketAuthority.emitter('series_added', seriesItem.toOldJSON())
|
||||||
}
|
}
|
||||||
seriesPayload.push(seriesItem.toJSONMinimal(seriesMatchItem.sequence))
|
seriesPayload.push(seriesItem.toJSONMinimal(seriesMatchItem.sequence))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ module.exports = {
|
|||||||
* @param {import('../../models/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {{ series:import('../../objects/entities/Series')[], count:number}}
|
* @returns {{ series:any[], count:number}}
|
||||||
*/
|
*/
|
||||||
async getSeriesMostRecentlyAdded(library, user, include, limit) {
|
async getSeriesMostRecentlyAdded(library, user, include, limit) {
|
||||||
if (!library.isBook) return { series: [], count: 0 }
|
if (!library.isBook) return { series: [], count: 0 }
|
||||||
@@ -276,7 +276,7 @@ module.exports = {
|
|||||||
|
|
||||||
const allOldSeries = []
|
const allOldSeries = []
|
||||||
for (const s of series) {
|
for (const s of series) {
|
||||||
const oldSeries = s.getOldSeries().toJSON()
|
const oldSeries = s.toOldJSON()
|
||||||
|
|
||||||
if (s.feeds?.length) {
|
if (s.feeds?.length) {
|
||||||
oldSeries.rssFeed = Database.feedModel.getOldFeed(s.feeds[0]).toJSONMinified()
|
oldSeries.rssFeed = Database.feedModel.getOldFeed(s.feeds[0]).toJSONMinified()
|
||||||
|
|||||||
@@ -954,12 +954,12 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get library items for series
|
* Get library items for series
|
||||||
* @param {import('../../objects/entities/Series')} oldSeries
|
* @param {import('../../models/Series')} series
|
||||||
* @param {import('../../models/User')} [user]
|
* @param {import('../../models/User')} [user]
|
||||||
* @returns {Promise<import('../../objects/LibraryItem')[]>}
|
* @returns {Promise<import('../../objects/LibraryItem')[]>}
|
||||||
*/
|
*/
|
||||||
async getLibraryItemsForSeries(oldSeries, user) {
|
async getLibraryItemsForSeries(series, user) {
|
||||||
const { libraryItems } = await this.getFilteredLibraryItems(oldSeries.libraryId, user, 'series', oldSeries.id, null, null, false, [], null, null)
|
const { libraryItems } = await this.getFilteredLibraryItems(series.libraryId, user, 'series', series.id, null, null, false, [], null, null)
|
||||||
return libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
|
return libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1130,7 +1130,7 @@ module.exports = {
|
|||||||
return Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSON()
|
return Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSON()
|
||||||
})
|
})
|
||||||
seriesMatches.push({
|
seriesMatches.push({
|
||||||
series: series.getOldSeries().toJSON(),
|
series: series.toOldJSON(),
|
||||||
books
|
books
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ module.exports = {
|
|||||||
// Map series to old series
|
// Map series to old series
|
||||||
const allOldSeries = []
|
const allOldSeries = []
|
||||||
for (const s of series) {
|
for (const s of series) {
|
||||||
const oldSeries = s.getOldSeries().toJSON()
|
const oldSeries = s.toOldJSON()
|
||||||
|
|
||||||
if (s.dataValues.totalDuration) {
|
if (s.dataValues.totalDuration) {
|
||||||
oldSeries.totalDuration = s.dataValues.totalDuration
|
oldSeries.totalDuration = s.dataValues.totalDuration
|
||||||
|
|||||||
Reference in New Issue
Block a user