mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-06-03 17:30:39 +02:00
Compare commits
247 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b39268ccb0 | |||
| de8a9304d2 | |||
| f8fbd3ac8c | |||
| 369c05936b | |||
| 837a180dc1 | |||
| 302b651e7b | |||
| 4c68ad46f4 | |||
| e50bd93958 | |||
| d576625cb7 | |||
| ca2327aba3 | |||
| 9bd1f9e3d5 | |||
| c4610e6102 | |||
| 329bbea043 | |||
| e616b53877 | |||
| eab86f90a8 | |||
| f97389cb2b | |||
| c5c3aab130 | |||
| 4610e58337 | |||
| 190a1000d9 | |||
| 455b96d1ab | |||
| 8aaf62f243 | |||
| e6d754113e | |||
| 5f72e30e63 | |||
| 57906540fe | |||
| 726adbb3bf | |||
| f7b7b85673 | |||
| 5646466aa3 | |||
| b38ce41731 | |||
| a8ab8badd5 | |||
| 5eca43082e | |||
| 6fa11934be | |||
| ff7edc32a1 | |||
| 9b8e059efe | |||
| 7486d6345d | |||
| 835490a9fc | |||
| 3b4a5b8785 | |||
| 9a1c773b7a | |||
| 890b0b949e | |||
| b19e360bbb | |||
| 1ff7952074 | |||
| 259d93d882 | |||
| 14f60a593b | |||
| 7334580c8c | |||
| f467c44543 | |||
| 867354e59d | |||
| 67952cc577 | |||
| 079a15541c | |||
| 658ac04268 | |||
| cbee6d8f5e | |||
| 68413ae2f6 | |||
| 252a233282 | |||
| c35185fff7 | |||
| 9774b2cfa5 | |||
| 344890fb45 | |||
| 5fa0897ad7 | |||
| 95c80a5b18 | |||
| 0f1b64b883 | |||
| 615ed26f0f | |||
| 84803cef82 | |||
| 605bd73c11 | |||
| cc89db059b | |||
| a03146e09c | |||
| 33aa4f1952 | |||
| c03f18b90a | |||
| 0dedb09a07 | |||
| 2b5484243b | |||
| c496db7c95 | |||
| ea4d5ff665 | |||
| 468a547864 | |||
| cd9999d192 | |||
| 31e302ea59 | |||
| 1ff1ba66fd | |||
| a5457d7e22 | |||
| ddcbfd4500 | |||
| 293e530297 | |||
| 7278ad4ee7 | |||
| 0449fb5ef9 | |||
| d2c28fc69c | |||
| 60ba0163af | |||
| 02ca926d88 | |||
| 4b52f31d58 | |||
| 9917f2d358 | |||
| 8c3ba67583 | |||
| 6d8720b404 | |||
| 843dd0b1b2 | |||
| 70f466d03c | |||
| ef82e8b0d0 | |||
| c643d4cec8 | |||
| 718d8b5999 | |||
| 2ba0f9157d | |||
| 53fdb5273c | |||
| fabdfd5517 | |||
| 950993f652 | |||
| 5a968b002a | |||
| 3acd29fab3 | |||
| 315b21db00 | |||
| f9aaeb3a34 | |||
| d19bb909b3 | |||
| f850db23fe | |||
| 5f81010f6a | |||
| daf2493f50 | |||
| 57222f3611 | |||
| 62b185979e | |||
| ebcc85acc4 | |||
| 33a7ba4acd | |||
| 1d4e6993fc | |||
| 784b761629 | |||
| 268fb2ce9a | |||
| fc5f35b388 | |||
| ff026a06bb | |||
| b148a57c98 | |||
| ee6e2d2983 | |||
| ea3a6fd75e | |||
| 22f85d3af9 | |||
| 75f4c2ee99 | |||
| dd3467efa2 | |||
| 4adb15c11b | |||
| a5e38d1473 | |||
| 778256ca16 | |||
| 2b0ba7d1e2 | |||
| 772f3fedb3 | |||
| fe25d1dccd | |||
| 10a7cd0987 | |||
| 6786df6965 | |||
| 4cfd18c81a | |||
| d25a21cd32 | |||
| b5f0a6f4a6 | |||
| cf19dd23cf | |||
| 3e6a2d670e | |||
| 26ef33a4b6 | |||
| 9940f1d6db | |||
| 75eef8d722 | |||
| 46a3c3de33 | |||
| 2b7e3f0efe | |||
| d5fbc1d455 | |||
| bbe59499ad | |||
| 4c88e9c8d2 | |||
| 5ccf5d7150 | |||
| 45f8b06d56 | |||
| 2a62992c75 | |||
| 997afc1b2f | |||
| f941ea6500 | |||
| 92d083164f | |||
| 2dd30c7a26 | |||
| 3f0347253e | |||
| bb6377fb22 | |||
| 12c2071358 | |||
| ec4c4a4d5a | |||
| 876fcf3296 | |||
| 023ceed286 | |||
| cc42aa32ef | |||
| 7cbb1c60a2 | |||
| 4ad130a11a | |||
| 9bf46b6367 | |||
| 4be2909b24 | |||
| f161158d83 | |||
| 3a5f6ab6f1 | |||
| c1b626da14 | |||
| 48e0a3c450 | |||
| 8626fa3e00 | |||
| b50d7f0927 | |||
| 0d54b57151 | |||
| 5a2bdc58da | |||
| 01446c02aa | |||
| a382482173 | |||
| 2e970cbb39 | |||
| 161a3f4da9 | |||
| 713bdcbc41 | |||
| 1fa67535f9 | |||
| e8d8b67c0a | |||
| e57d4cc544 | |||
| 435b7fda7e | |||
| d7e810fc2f | |||
| 850ed48955 | |||
| a5ebd89817 | |||
| a8ec07cfc9 | |||
| 41fe5373a7 | |||
| 0c244cbf95 | |||
| 7ef14aabed | |||
| 978c2b05f2 | |||
| 68fd1d67cb | |||
| bf8407274e | |||
| 3bc2941445 | |||
| 654b1d6b34 | |||
| 7a49681dd2 | |||
| 7a1623e6a1 | |||
| c25acb41fa | |||
| 4224b8a486 | |||
| 9e990d7927 | |||
| 431ae97593 | |||
| 633ff810cf | |||
| f3d2b781ab | |||
| 32105665c1 | |||
| 2b18efdfdc | |||
| e0c66ea6df | |||
| 667c7361d7 | |||
| 63fdf0d18e | |||
| e05cb0ef4d | |||
| 925c7f7dc7 | |||
| c69e97ea24 | |||
| 5e2aebc724 | |||
| 6eba467b91 | |||
| 524cf5ec5b | |||
| 50fd659749 | |||
| 8169afb59b | |||
| d40086fea1 | |||
| 399c40debd | |||
| d986673dfd | |||
| f83f4d41f1 | |||
| 7ed711730e | |||
| 94e2ea9df3 | |||
| 8c8c4a15c3 | |||
| 2a9159f106 | |||
| 8f113d17c2 | |||
| 9084055b95 | |||
| fba9cce82e | |||
| 92cfb46c14 | |||
| 449dc1a0e2 | |||
| d9c345b0f3 | |||
| 69a639f76c | |||
| d576efe759 | |||
| 9ba2ecbc21 | |||
| 84003cd67e | |||
| be8c447216 | |||
| e534daf5d4 | |||
| 1fefc1af92 | |||
| e76c4ed2a4 | |||
| e1caf13233 | |||
| a7a2fbbca8 | |||
| 28d93d9160 | |||
| 4e90f90c28 | |||
| 2243fdddd3 | |||
| 39be3a2ef9 | |||
| ecc30b85bc | |||
| 6905b288d2 | |||
| 0782146682 | |||
| 91aea4f754 | |||
| 6ca277a21d | |||
| c47c75aefe | |||
| 9896e4381b | |||
| 953ffe889e | |||
| 72e59e77a7 | |||
| 35e2681ea9 | |||
| 84012d9090 | |||
| e8a1ea3b54 | |||
| ea6882d9ab | |||
| 1fa80e31d1 |
@@ -0,0 +1,33 @@
|
|||||||
|
<!--
|
||||||
|
For Work In Progress Pull Requests, please use the Draft PR feature,
|
||||||
|
see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
|
||||||
|
|
||||||
|
If you do not follow this template, the PR may be closed without review.
|
||||||
|
|
||||||
|
Please ensure all checks pass.
|
||||||
|
If you are a new contributor, the workflows will need to be manually approved before they run.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Brief summary
|
||||||
|
|
||||||
|
<!-- Please provide a brief summary of what your PR attempts to achieve. -->
|
||||||
|
|
||||||
|
## Which issue is fixed?
|
||||||
|
|
||||||
|
<!-- Which issue number does this PR fix? Ex: "Fixes #1234" -->
|
||||||
|
|
||||||
|
## In-depth Description
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Describe your solution in more depth.
|
||||||
|
How does it work? Why is this the best solution?
|
||||||
|
Does it solve a problem that affects multiple users or is this an edge case for your setup?
|
||||||
|
-->
|
||||||
|
|
||||||
|
## How have you tested this?
|
||||||
|
|
||||||
|
<!-- Please describe in detail with reproducible steps how you tested your changes. -->
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<!-- If your PR includes any changes to the web client, please include screenshots or a short video from before and after your changes. -->
|
||||||
@@ -1,11 +1,25 @@
|
|||||||
name: "CodeQL"
|
name: 'CodeQL'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ 'master' ]
|
branches: ['master']
|
||||||
|
# Only build when files in these directories have been changed
|
||||||
|
paths:
|
||||||
|
- client/**
|
||||||
|
- server/**
|
||||||
|
- test/**
|
||||||
|
- index.js
|
||||||
|
- package.json
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ 'master' ]
|
branches: ['master']
|
||||||
|
# Only build when files in these directories have been changed
|
||||||
|
paths:
|
||||||
|
- client/**
|
||||||
|
- server/**
|
||||||
|
- test/**
|
||||||
|
- index.js
|
||||||
|
- package.json
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '16 5 * * 4'
|
- cron: '16 5 * * 4'
|
||||||
|
|
||||||
@@ -21,45 +35,44 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: [ 'javascript' ]
|
language: ['javascript']
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
# By default, queries listed here will override any specified in a config file.
|
# By default, queries listed here will override any specified in a config file.
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
# queries: security-extended,security-and-quality
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v2
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
# - run: |
|
||||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
# - run: |
|
- name: Perform CodeQL Analysis
|
||||||
# echo "Run, Build Application using script"
|
uses: github/codeql-action/analyze@v2
|
||||||
# ./location_of_script_within_repo/buildscript.sh
|
with:
|
||||||
|
category: '/language:${{matrix.language}}'
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
||||||
with:
|
|
||||||
category: "/language:${{matrix.language}}"
|
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- 'dependabot/**' # Don't run dependabot branches, as they are already covered by pull requests
|
- 'dependabot/**' # Don't run dependabot branches, as they are already covered by pull requests
|
||||||
|
# Only build when files in these directories have been changed
|
||||||
|
paths:
|
||||||
|
- client/**
|
||||||
|
- server/**
|
||||||
|
- test/**
|
||||||
|
- index.js
|
||||||
|
- package.json
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-16 bg-primary relative">
|
<div class="w-full h-16 bg-primary relative">
|
||||||
<div id="appbar" class="absolute top-0 bottom-0 left-0 w-full h-full px-2 md:px-6 py-1 z-60">
|
<div id="appbar" role="toolbar" aria-label="Appbar" class="absolute top-0 bottom-0 left-0 w-full h-full px-2 md:px-6 py-1 z-60">
|
||||||
<div class="flex h-full items-center">
|
<div class="flex h-full items-center">
|
||||||
<nuxt-link to="/">
|
<nuxt-link to="/">
|
||||||
<img src="~static/icon.svg" :alt="$strings.ButtonHome" class="w-8 min-w-8 h-8 mr-2 sm:w-10 sm:min-w-10 sm:h-10 sm:mr-4" />
|
<img src="~static/icon.svg" :alt="$strings.ButtonHome" class="w-8 min-w-8 h-8 mr-2 sm:w-10 sm:min-w-10 sm:h-10 sm:mr-4" />
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<div v-else-if="isAlternativeBookshelfView" class="w-full mb-24e">
|
<div v-else-if="isAlternativeBookshelfView" class="w-full mb-24e">
|
||||||
<template v-for="(shelf, index) in supportedShelves">
|
<template v-for="(shelf, index) in supportedShelves">
|
||||||
<widgets-item-slider :shelf-id="shelf.id" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening' || shelf.id === 'continue-reading'" :type="shelf.type" class="bookshelf-row pl-8e my-6e" @selectEntity="(payload) => selectEntity(payload, index)">
|
<widgets-item-slider :shelf-id="shelf.id" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening' || shelf.id === 'continue-reading'" :type="shelf.type" class="bookshelf-row pl-8e my-6e" @selectEntity="(payload) => selectEntity(payload, index)">
|
||||||
<p class="font-semibold text-gray-100">{{ $strings[shelf.labelStringKey] }}</p>
|
<h2 class="font-semibold text-gray-100">{{ $strings[shelf.labelStringKey] }}</h2>
|
||||||
</widgets-item-slider>
|
</widgets-item-slider>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,18 +37,18 @@
|
|||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div class="relative text-center categoryPlacard transform z-30 top-0 left-4e md:left-8e w-44e rounded-md">
|
<div class="relative text-center categoryPlacard transform z-30 top-0 left-4e md:left-8e w-44e rounded-md">
|
||||||
<div class="w-full h-full shinyBlack flex items-center justify-center rounded-sm border" :style="{ padding: `0em 0.5em` }">
|
<div class="w-full h-full shinyBlack flex items-center justify-center rounded-sm border" :style="{ padding: `0em 0.5em` }">
|
||||||
<p :style="{ fontSize: 0.9 + 'em' }">{{ $strings[shelf.labelStringKey] }}</p>
|
<h2 :style="{ fontSize: 0.9 + 'em' }">{{ $strings[shelf.labelStringKey] }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bookshelfDividerCategorized h-6e w-full absolute top-0 left-0 right-0 z-20"></div>
|
<div class="bookshelfDividerCategorized h-6e w-full absolute top-0 left-0 right-0 z-20"></div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="canScrollLeft && !isScrolling" class="hidden sm:flex absolute top-0 left-0 w-32 pr-8 bg-black book-shelf-arrow-left items-center justify-center cursor-pointer opacity-0 hover:opacity-100 z-40" @click="scrollLeft">
|
<button v-show="canScrollLeft && !isScrolling" :aria-label="$strings.ButtonScrollLeft" class="hidden sm:flex absolute top-0 left-0 w-32 pr-8 bg-black book-shelf-arrow-left items-center justify-center cursor-pointer opacity-0 hover:opacity-100 z-40" @click="scrollLeft">
|
||||||
<span class="material-symbols text-white" :style="{ fontSize: 3.75 + 'em' }">chevron_left</span>
|
<span class="material-symbols text-white" :style="{ fontSize: 3.75 + 'em' }">chevron_left</span>
|
||||||
</div>
|
</button>
|
||||||
<div v-show="canScrollRight && !isScrolling" class="hidden sm:flex absolute top-0 right-0 w-32 pl-8 bg-black book-shelf-arrow-right items-center justify-center cursor-pointer opacity-0 hover:opacity-100 z-40" @click="scrollRight">
|
<button v-show="canScrollRight && !isScrolling" :aria-label="$strings.ButtonScrollRight" class="hidden sm:flex absolute top-0 right-0 w-32 pl-8 bg-black book-shelf-arrow-right items-center justify-center cursor-pointer opacity-0 hover:opacity-100 z-40" @click="scrollRight">
|
||||||
<span class="material-symbols text-white" :style="{ fontSize: 3.75 + 'em' }">chevron_right</span>
|
<span class="material-symbols text-white" :style="{ fontSize: 3.75 + 'em' }">chevron_right</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<p class="text-sm">{{ $strings.ButtonAdd }}</p>
|
<p class="text-sm">{{ $strings.ButtonAdd }}</p>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
<div id="toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-40 flex items-center justify-end md:justify-start px-2 md:px-8">
|
<div id="toolbar" role="toolbar" aria-label="Library Toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-40 flex items-center justify-end md:justify-start px-2 md:px-8">
|
||||||
<!-- Series books page -->
|
<!-- Series books page -->
|
||||||
<template v-if="selectedSeries">
|
<template v-if="selectedSeries">
|
||||||
<p class="pl-2 text-base md:text-lg">
|
<p class="pl-2 text-base md:text-lg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div role="toolbar" aria-orientation="vertical" aria-label="Config Sidebar">
|
||||||
<div class="w-44 fixed left-0 top-16 bg-bg bg-opacity-100 md:bg-opacity-70 shadow-lg border-r border-white border-opacity-5 py-3 transform transition-transform mb-12 overflow-y-auto" :class="wrapperClass + ' ' + (streamLibraryItem ? 'h-[calc(100%-270px)]' : 'h-[calc(100%-110px)]')" v-click-outside="clickOutside">
|
<div role="navigation" aria-label="Config Navigation" class="w-44 fixed left-0 top-16 bg-bg bg-opacity-100 md:bg-opacity-70 shadow-lg border-r border-white border-opacity-5 py-3 transform transition-transform mb-12 overflow-y-auto" :class="wrapperClass + ' ' + (streamLibraryItem ? 'h-[calc(100%-270px)]' : 'h-[calc(100%-110px)]')" v-click-outside="clickOutside">
|
||||||
<div v-show="isMobilePortrait" class="flex items-center justify-end pb-2 px-4 mb-1" @click="closeDrawer">
|
<div v-show="isMobilePortrait" class="flex items-center justify-end pb-2 px-4 mb-1" @click="closeDrawer">
|
||||||
<span class="material-symbols text-2xl">arrow_back</span>
|
<span class="material-symbols text-2xl">arrow_back</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<p class="text-xs text-gray-300 italic">{{ Source }}</p>
|
<p class="text-xs text-gray-300 italic">{{ Source }}</p>
|
||||||
</div>
|
</div>
|
||||||
<a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ $config.version }}</a>
|
<a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ versionData.latestVersion }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
@showBookmarks="showBookmarks"
|
@showBookmarks="showBookmarks"
|
||||||
@showSleepTimer="showSleepTimerModal = true"
|
@showSleepTimer="showSleepTimerModal = true"
|
||||||
@showPlayerQueueItems="showPlayerQueueItemsModal = true"
|
@showPlayerQueueItems="showPlayerQueueItemsModal = true"
|
||||||
@showPlayerSettings="showPlayerSettingsModal = true"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<modals-bookmarks-modal v-model="showBookmarksModal" :bookmarks="bookmarks" :current-time="bookmarkCurrentTime" :library-item-id="libraryItemId" @select="selectBookmark" />
|
<modals-bookmarks-modal v-model="showBookmarksModal" :bookmarks="bookmarks" :current-time="bookmarkCurrentTime" :library-item-id="libraryItemId" @select="selectBookmark" />
|
||||||
@@ -61,8 +60,6 @@
|
|||||||
<modals-sleep-timer-modal v-model="showSleepTimerModal" :timer-set="sleepTimerSet" :timer-type="sleepTimerType" :remaining="sleepTimerRemaining" :has-chapters="!!chapters.length" @set="setSleepTimer" @cancel="cancelSleepTimer" @increment="incrementSleepTimer" @decrement="decrementSleepTimer" />
|
<modals-sleep-timer-modal v-model="showSleepTimerModal" :timer-set="sleepTimerSet" :timer-type="sleepTimerType" :remaining="sleepTimerRemaining" :has-chapters="!!chapters.length" @set="setSleepTimer" @cancel="cancelSleepTimer" @increment="incrementSleepTimer" @decrement="decrementSleepTimer" />
|
||||||
|
|
||||||
<modals-player-queue-items-modal v-model="showPlayerQueueItemsModal" />
|
<modals-player-queue-items-modal v-model="showPlayerQueueItemsModal" />
|
||||||
|
|
||||||
<modals-player-settings-modal v-model="showPlayerSettingsModal" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -81,7 +78,6 @@ export default {
|
|||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
showSleepTimerModal: false,
|
showSleepTimerModal: false,
|
||||||
showPlayerQueueItemsModal: false,
|
showPlayerQueueItemsModal: false,
|
||||||
showPlayerSettingsModal: false,
|
|
||||||
sleepTimerSet: false,
|
sleepTimerSet: false,
|
||||||
sleepTimerRemaining: 0,
|
sleepTimerRemaining: 0,
|
||||||
sleepTimerType: null,
|
sleepTimerType: null,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-20 bg-bg h-full fixed left-0 box-shadow-side z-50" style="min-width: 80px" :style="{ top: offsetTop + 'px' }">
|
<div role="toolbar" aria-orientation="vertical" aria-label="Library Sidebar" class="w-20 bg-bg h-full fixed left-0 box-shadow-side z-50" style="min-width: 80px" :style="{ top: offsetTop + 'px' }">
|
||||||
<!-- ugly little workaround to cover up the shadow overlapping the bookshelf toolbar -->
|
<!-- ugly little workaround to cover up the shadow overlapping the bookshelf toolbar -->
|
||||||
<div v-if="isShowingBookshelfToolbar" class="absolute top-0 -right-4 w-4 bg-bg h-10 pointer-events-none" />
|
<div v-if="isShowingBookshelfToolbar" class="absolute top-0 -right-4 w-4 bg-bg h-10 pointer-events-none" />
|
||||||
|
|
||||||
<div id="siderail-buttons-container" :class="{ 'player-open': streamLibraryItem }" class="w-full overflow-y-auto overflow-x-hidden">
|
<div id="siderail-buttons-container" role="navigation" aria-label="Library Navigation" :class="{ 'player-open': streamLibraryItem }" class="w-full overflow-y-auto overflow-x-hidden">
|
||||||
<nuxt-link :to="`/library/${currentLibraryId}`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="homePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
<nuxt-link :to="`/library/${currentLibraryId}`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="homePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pb-3e" :style="{ minWidth: cardWidth + 'px', maxWidth: cardWidth + 'px' }">
|
<article class="pb-3e" :style="{ minWidth: cardWidth + 'px', maxWidth: cardWidth + 'px' }">
|
||||||
<nuxt-link :to="`/author/${author?.id}`">
|
<nuxt-link :to="`/author/${author?.id}`">
|
||||||
<div cy-id="card" @mouseover="mouseover" @mouseleave="mouseleave">
|
<div cy-id="card" @mouseover="mouseover" @mouseleave="mouseleave">
|
||||||
<div cy-id="imageArea" :style="{ height: cardHeight + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden">
|
<div cy-id="imageArea" :style="{ height: cardHeight + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden">
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</div>
|
</article>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="card" :id="`book-card-${index}`" :style="{ minWidth: coverWidth + 'px', maxWidth: coverWidth + 'px' }" class="absolute rounded-sm z-10 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
<article ref="card" :id="`book-card-${index}`" tabindex="0" :aria-label="displayTitle" :style="{ minWidth: coverWidth + 'px', maxWidth: coverWidth + 'px' }" class="absolute rounded-sm z-10 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
||||||
<div :id="`cover-area-${index}`" class="relative w-full top-0 left-0 rounded overflow-hidden z-10 bg-primary box-shadow-book" :style="{ height: coverHeight + 'px ' }">
|
<div :id="`cover-area-${index}`" class="relative w-full top-0 left-0 rounded overflow-hidden z-10 bg-primary box-shadow-book" :style="{ height: coverHeight + 'px ' }">
|
||||||
<!-- When cover image does not fill -->
|
<!-- When cover image does not fill -->
|
||||||
<div cy-id="coverBg" v-show="showCoverBg" class="absolute top-0 left-0 w-full h-full overflow-hidden rounded-sm bg-primary">
|
<div cy-id="coverBg" v-show="showCoverBg" class="absolute top-0 left-0 w-full h-full overflow-hidden rounded-sm bg-primary">
|
||||||
@@ -14,21 +14,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full h-full absolute top-0 left-0 rounded overflow-hidden z-10">
|
<div class="w-full h-full absolute top-0 left-0 rounded overflow-hidden z-10">
|
||||||
<div cy-id="titleImageNotReady" v-show="libraryItem && !imageReady" class="absolute top-0 left-0 w-full h-full flex items-center justify-center" :style="{ padding: 0.5 + 'em' }">
|
<div cy-id="titleImageNotReady" v-show="libraryItem && !imageReady" aria-hidden="true" class="absolute top-0 left-0 w-full h-full flex items-center justify-center" :style="{ padding: 0.5 + 'em' }">
|
||||||
<p :style="{ fontSize: 0.8 + 'em' }" class="text-gray-300 text-center">{{ title }}</p>
|
<p :style="{ fontSize: 0.8 + 'em' }" class="text-gray-300 text-center">{{ title }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cover Image -->
|
<!-- Cover Image -->
|
||||||
<img cy-id="coverImage" v-show="libraryItem" ref="cover" :src="bookCoverSrc" class="relative w-full h-full transition-opacity duration-300" :class="showCoverBg ? 'object-contain' : 'object-fill'" @load="imageLoaded" :style="{ opacity: imageReady ? 1 : 0 }" />
|
<img cy-id="coverImage" v-show="libraryItem" :alt="`${displayTitle}, ${$strings.LabelCover}`" ref="cover" aria-hidden="true" :src="bookCoverSrc" class="relative w-full h-full transition-opacity duration-300" :class="showCoverBg ? 'object-contain' : 'object-fill'" @load="imageLoaded" :style="{ opacity: imageReady ? 1 : 0 }" />
|
||||||
|
|
||||||
<!-- Placeholder Cover Title & Author -->
|
<!-- Placeholder Cover Title & Author -->
|
||||||
<div cy-id="placeholderTitle" v-if="!hasCover" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full flex items-center justify-center" :style="{ padding: placeholderCoverPadding + 'em' }">
|
<div cy-id="placeholderTitle" v-if="!hasCover" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full flex items-center justify-center" :style="{ padding: placeholderCoverPadding + 'em' }">
|
||||||
<div>
|
<div>
|
||||||
<p cy-id="placeholderTitleText" class="text-center" style="color: rgb(247 223 187)" :style="{ fontSize: titleFontSize + 'em' }">{{ titleCleaned }}</p>
|
<p cy-id="placeholderTitleText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187)" :style="{ fontSize: titleFontSize + 'em' }">{{ titleCleaned }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div cy-id="placeholderAuthor" v-if="!hasCover" class="absolute left-0 right-0 w-full flex items-center justify-center" :style="{ padding: placeholderCoverPadding + 'em', bottom: authorBottom + 'em' }">
|
<div cy-id="placeholderAuthor" v-if="!hasCover" class="absolute left-0 right-0 w-full flex items-center justify-center" :style="{ padding: placeholderCoverPadding + 'em', bottom: authorBottom + 'em' }">
|
||||||
<p cy-id="placeholderAuthorText" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
|
<p cy-id="placeholderAuthorText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="seriesSequenceList" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20 text-right" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #78350f">
|
<div v-if="seriesSequenceList" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20 text-right" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #78350f">
|
||||||
@@ -93,11 +93,11 @@
|
|||||||
|
|
||||||
<!-- rss feed icon -->
|
<!-- rss feed icon -->
|
||||||
<div cy-id="rssFeed" v-if="rssFeed && !isSelectionMode && !isHovering" class="absolute text-success top-0 left-0 z-10" :style="{ padding: 0.375 + 'em' }">
|
<div cy-id="rssFeed" v-if="rssFeed && !isSelectionMode && !isHovering" class="absolute text-success top-0 left-0 z-10" :style="{ padding: 0.375 + 'em' }">
|
||||||
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">rss_feed</span>
|
<span class="material-symbols" aria-hidden="true" :style="{ fontSize: 1.5 + 'em' }">rss_feed</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- media item shared icon -->
|
<!-- media item shared icon -->
|
||||||
<div cy-id="mediaItemShare" v-if="mediaItemShare && !isSelectionMode && !isHovering" class="absolute text-success left-0 z-10" :style="{ padding: 0.375 + 'em', top: rssFeed ? '2em' : '0px' }">
|
<div cy-id="mediaItemShare" v-if="mediaItemShare && !isSelectionMode && !isHovering" class="absolute text-success left-0 z-10" :style="{ padding: 0.375 + 'em', top: rssFeed ? '2em' : '0px' }">
|
||||||
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">public</span>
|
<span class="material-symbols" aria-hidden="true" :style="{ fontSize: 1.5 + 'em' }">public</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Series sequence -->
|
<!-- Series sequence -->
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
|
|
||||||
<!-- Podcast Num Episodes -->
|
<!-- Podcast Num Episodes -->
|
||||||
<div cy-id="numEpisodes" v-else-if="!numEpisodesIncomplete && numEpisodes && !isHovering && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', width: 1.25 + 'em', height: 1.25 + 'em' }">
|
<div cy-id="numEpisodes" v-else-if="!numEpisodesIncomplete && numEpisodes && !isHovering && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', width: 1.25 + 'em', height: 1.25 + 'em' }">
|
||||||
<p :style="{ fontSize: 0.8 + 'em' }">{{ numEpisodes }}</p>
|
<p :style="{ fontSize: 0.8 + 'em' }" role="status" :aria-label="$strings.LabelNumberOfEpisodes">{{ numEpisodes }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Podcast Num Episodes -->
|
<!-- Podcast Num Episodes -->
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
<div cy-id="detailBottom" :id="`description-area-${index}`" v-if="isAlternativeBookshelfView || isAuthorBookshelfView" dir="auto" class="relative mt-2e mb-2e left-0 z-50 w-full">
|
<div cy-id="detailBottom" :id="`description-area-${index}`" v-if="isAlternativeBookshelfView || isAuthorBookshelfView" dir="auto" class="relative mt-2e mb-2e left-0 z-50 w-full">
|
||||||
<div :style="{ fontSize: 0.9 + 'em' }">
|
<div :style="{ fontSize: 0.9 + 'em' }">
|
||||||
<ui-tooltip v-if="displayTitle" :text="displayTitle" :disabled="!displayTitleTruncated" direction="bottom" :delayOnShow="500" class="flex items-center">
|
<ui-tooltip v-if="displayTitle" :text="displayTitle" :disabled="!displayTitleTruncated" direction="bottom" :delayOnShow="500" class="flex items-center">
|
||||||
<p cy-id="title" ref="displayTitle" class="truncate">{{ displayTitle }}</p>
|
<p cy-id="title" ref="displayTitle" aria-hidden="true" class="truncate">{{ displayTitle }}</p>
|
||||||
<widgets-explicit-indicator cy-id="explicitIndicator" v-if="isExplicit" />
|
<widgets-explicit-indicator cy-id="explicitIndicator" v-if="isExplicit" />
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
<p cy-id="line2" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displayLineTwo || ' ' }}</p>
|
<p cy-id="line2" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displayLineTwo || ' ' }}</p>
|
||||||
<p cy-id="line3" v-if="displaySortLine" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displaySortLine }}</p>
|
<p cy-id="line3" v-if="displaySortLine" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displaySortLine }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="card" :id="`collection-card-${index}`" :style="{ width: cardWidth + 'px' }" class="absolute top-0 left-0 rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
<div ref="card" :id="`collection-card-${index}`" role="button" :style="{ width: cardWidth + 'px' }" class="absolute top-0 left-0 rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
||||||
<div class="relative" :style="{ height: coverHeight + 'px' }">
|
<div class="relative" :style="{ height: coverHeight + 'px' }">
|
||||||
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
||||||
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="card" :id="`playlist-card-${index}`" :style="{ width: cardWidth + 'px', fontSize: sizeMultiplier + 'rem' }" class="absolute top-0 left-0 rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
<div ref="card" :id="`playlist-card-${index}`" role="button" :style="{ width: cardWidth + 'px', fontSize: sizeMultiplier + 'rem' }" class="absolute top-0 left-0 rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
||||||
<div class="relative" :style="{ height: coverHeight + 'px' }">
|
<div class="relative" :style="{ height: coverHeight + 'px' }">
|
||||||
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
||||||
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div cy-id="card" ref="card" :id="`series-card-${index}`" :style="{ width: cardWidth + 'px' }" class="absolute rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
<article cy-id="card" ref="card" :id="`series-card-${index}`" tabindex="0" :aria-label="displayTitle" :style="{ width: cardWidth + 'px' }" class="absolute rounded-sm z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
|
||||||
<div cy-id="covers-area" class="relative" :style="{ height: coverHeight + 'px' }">
|
<div cy-id="covers-area" class="relative" :style="{ height: coverHeight + 'px' }">
|
||||||
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
||||||
<div class="w-full h-full bg-primary relative rounded overflow-hidden z-0">
|
<div class="w-full h-full bg-primary relative rounded overflow-hidden z-0">
|
||||||
@@ -7,12 +7,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div cy-id="seriesLengthMarker" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `0.1em 0.25em` }" style="background-color: #cd9d49dd">
|
<div cy-id="seriesLengthMarker" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `0.1em 0.25em` }" style="background-color: #cd9d49dd">
|
||||||
<p :style="{ fontSize: 0.8 + 'em' }">{{ books.length }}</p>
|
<p :style="{ fontSize: 0.8 + 'em' }" role="status" :aria-label="$strings.LabelNumberOfBooks">{{ books.length }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div cy-id="seriesProgressBar" v-if="seriesPercentInProgress > 0" class="absolute bottom-0 left-0 h-1e shadow-sm max-w-full z-10 rounded-b w-full" :class="isSeriesFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: seriesPercentInProgress * 100 + '%' }" />
|
<div cy-id="seriesProgressBar" v-if="seriesPercentInProgress > 0" class="absolute bottom-0 left-0 h-1e shadow-sm max-w-full z-10 rounded-b w-full" :class="isSeriesFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: seriesPercentInProgress * 100 + '%' }" />
|
||||||
|
|
||||||
<div cy-id="hoveringDisplayTitle" v-if="hasValidCovers" class="bg-black bg-opacity-60 absolute top-0 left-0 w-full h-full flex items-center justify-center text-center transition-opacity" :class="isHovering ? '' : 'opacity-0'" :style="{ padding: '1em' }">
|
<div cy-id="hoveringDisplayTitle" v-if="hasValidCovers" aria-hidden="true" class="bg-black bg-opacity-60 absolute top-0 left-0 w-full h-full flex items-center justify-center text-center transition-opacity" :class="isHovering ? '' : 'opacity-0'" :style="{ padding: '1em' }">
|
||||||
<p :style="{ fontSize: 1.2 + 'em' }">{{ displayTitle }}</p>
|
<p :style="{ fontSize: 1.2 + 'em' }">{{ displayTitle }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
|
|
||||||
<div cy-id="standardBottomText" v-if="!isAlternativeBookshelfView" class="categoryPlacard absolute z-10 left-0 right-0 mx-auto -bottom-6e h-6e rounded-md text-center" :style="{ width: Math.min(200, cardWidth) + 'px' }">
|
<div cy-id="standardBottomText" v-if="!isAlternativeBookshelfView" class="categoryPlacard absolute z-10 left-0 right-0 mx-auto -bottom-6e h-6e rounded-md text-center" :style="{ width: Math.min(200, cardWidth) + 'px' }">
|
||||||
<div class="w-full h-full shinyBlack flex items-center justify-center rounded-sm border" :style="{ padding: `0em 0.5em` }">
|
<div class="w-full h-full shinyBlack flex items-center justify-center rounded-sm border" :style="{ padding: `0em 0.5em` }">
|
||||||
<p cy-id="standardBottomDisplayTitle" class="truncate" :style="{ fontSize: labelFontSize + 'em' }">{{ displayTitle }}</p>
|
<p cy-id="standardBottomDisplayTitle" class="truncate" aria-hidden="true" :style="{ fontSize: labelFontSize + 'em' }">{{ displayTitle }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div cy-id="detailBottomText" v-else class="relative z-30 left-0 right-0 mx-auto py-1e rounded-md text-center">
|
<div cy-id="detailBottomText" v-else class="relative z-30 left-0 right-0 mx-auto py-1e rounded-md text-center">
|
||||||
<p cy-id="detailBottomDisplayTitle" class="truncate" :style="{ fontSize: labelFontSize + 'em' }">{{ displayTitle }}</p>
|
<p cy-id="detailBottomDisplayTitle" class="truncate" aria-hidden="true" :style="{ fontSize: labelFontSize + 'em' }">{{ displayTitle }}</p>
|
||||||
<p cy-id="detailBottomSortLine" v-if="displaySortLine" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displaySortLine }}</p>
|
<p cy-id="detailBottomSortLine" v-if="displaySortLine" class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ displaySortLine }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="w-full relative sm:w-80">
|
<div class="w-full relative sm:w-80">
|
||||||
<form @submit.prevent="submitSearch">
|
<form role="search" @submit.prevent="submitSearch">
|
||||||
<ui-text-input ref="input" v-model="search" :placeholder="$strings.PlaceholderSearch" @input="inputUpdate" @focus="focussed" @blur="blurred" class="w-full h-8 text-sm" />
|
<ui-text-input ref="input" v-model="search" :placeholder="$strings.PlaceholderSearch" @input="inputUpdate" @focus="focussed" @blur="blurred" class="w-full h-8 text-sm" />
|
||||||
</form>
|
</form>
|
||||||
<div class="absolute top-0 right-0 bottom-0 h-full flex items-center px-2 text-gray-400 cursor-pointer" @click="clickClear">
|
<button :aria-hidden="!search" class="absolute top-0 right-0 bottom-0 h-full flex items-center px-2 text-gray-400 cursor-pointer" @click="clickClear">
|
||||||
<span v-if="!search" class="material-symbols" style="font-size: 1.2rem"></span>
|
<span v-if="!search" class="material-symbols" style="font-size: 1.2rem"></span>
|
||||||
<span v-else class="material-symbols" style="font-size: 1.2rem">close</span>
|
<span v-else class="material-symbols" style="font-size: 1.2rem">close</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="showMenu && (lastSearch || isTyping)" class="absolute z-40 -mt-px w-full max-w-64 sm:max-w-80 sm:w-80 bg-bg border border-black-200 shadow-lg rounded-md py-1 px-2 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm globalSearchMenu">
|
<div v-show="showMenu && (lastSearch || isTyping)" class="absolute z-40 -mt-px w-full max-w-64 sm:max-w-80 sm:w-80 bg-bg border border-black-200 shadow-lg rounded-md py-1 px-2 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm globalSearchMenu" @mousedown.stop.prevent>
|
||||||
<ul class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
<ul class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
||||||
<li v-if="isTyping" class="py-2 px-2">
|
<li v-if="isTyping" class="py-2 px-2">
|
||||||
<p>{{ $strings.MessageThinking }}</p>
|
<p>{{ $strings.MessageThinking }}</p>
|
||||||
@@ -157,7 +157,7 @@ export default {
|
|||||||
clearTimeout(this.focusTimeout)
|
clearTimeout(this.focusTimeout)
|
||||||
this.focusTimeout = setTimeout(() => {
|
this.focusTimeout = setTimeout(() => {
|
||||||
this.showMenu = false
|
this.showMenu = false
|
||||||
}, 200)
|
}, 100)
|
||||||
},
|
},
|
||||||
async runSearch(value) {
|
async runSearch(value) {
|
||||||
this.lastSearch = value
|
this.lastSearch = value
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
||||||
<button type="button" class="relative w-full h-full bg-bg border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" @click.prevent="showMenu = !showMenu">
|
<div class="relative h-7">
|
||||||
<span class="flex items-center justify-between">
|
<button type="button" class="relative w-full h-full bg-bg border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="menu" :aria-expanded="showMenu" @click.prevent="showMenu = !showMenu">
|
||||||
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
<span class="flex items-center justify-between">
|
||||||
</span>
|
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<span v-if="selected === 'all'" class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
<span v-if="selected === 'all'" class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<div v-else class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer text-gray-400 hover:text-gray-200" @mousedown.stop @mouseup.stop @click.stop.prevent="clearSelected">
|
<button v-else :aria-label="$strings.ButtonClearFilter" class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer text-gray-400 hover:text-gray-200" @mousedown.stop @mouseup.stop @click.stop.prevent="clearSelected">
|
||||||
<span class="material-symbols" style="font-size: 1.1rem">close</span>
|
<span class="material-symbols" style="font-size: 1.1rem">close</span>
|
||||||
</div>
|
</button>
|
||||||
</button>
|
</div>
|
||||||
|
|
||||||
<div v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm libraryFilterMenu">
|
<div v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm libraryFilterMenu">
|
||||||
<ul v-show="!sublist" class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
<ul v-show="!sublist" class="h-full w-full" role="menu">
|
||||||
<template v-for="item in selectItems">
|
<template v-for="item in selectItems">
|
||||||
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="option" @click="clickedOption(item)">
|
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="menuitem" :aria-haspopup="item.sublist ? '' : 'menu'" @click="clickedOption(item)">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="font-normal ml-3 block truncate text-sm">{{ item.text }}</span>
|
<span class="font-normal ml-3 block truncate text-sm">{{ item.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.sublist" class="absolute right-1 top-0 bottom-0 h-full flex items-center">
|
<div v-if="item.sublist" class="absolute right-1 top-0 bottom-0 h-full flex items-center">
|
||||||
<span class="material-symbols text-2xl">arrow_right</span>
|
<span class="material-symbols text-2xl" :aria-label="$strings.LabelMore">arrow_right</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- selected checkmark icon -->
|
<!-- selected checkmark icon -->
|
||||||
<div v-if="item.value === selected" class="absolute inset-y-0 right-2 h-full flex items-center pointer-events-none">
|
<div v-if="item.value === selected" class="absolute inset-y-0 right-2 h-full flex items-center pointer-events-none">
|
||||||
@@ -31,8 +33,8 @@
|
|||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
<ul v-show="sublist" class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
<ul v-show="sublist" class="h-full w-full" role="menu">
|
||||||
<li class="text-gray-50 select-none relative py-2 pl-9 cursor-pointer hover:bg-white/5" role="option" @click="sublist = null">
|
<li class="text-gray-50 select-none relative py-2 pl-9 cursor-pointer hover:bg-white/5" role="menuitem" @click="sublist = null">
|
||||||
<div class="absolute left-1 top-0 bottom-0 h-full flex items-center">
|
<div class="absolute left-1 top-0 bottom-0 h-full flex items-center">
|
||||||
<span class="material-symbols text-2xl">arrow_left</span>
|
<span class="material-symbols text-2xl">arrow_left</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,13 +42,13 @@
|
|||||||
<span class="font-normal block truncate">{{ $strings.ButtonBack }}</span>
|
<span class="font-normal block truncate">{{ $strings.ButtonBack }}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="!sublistItems.length" class="text-gray-400 select-none relative px-2" role="option">
|
<li v-if="!sublistItems.length" class="text-gray-400 select-none relative px-2" role="menuitem">
|
||||||
<div class="flex items-center justify-center">
|
<div class="flex items-center justify-center">
|
||||||
<span class="font-normal block truncate py-2">{{ $getString('LabelLibraryFilterSublistEmpty', [selectedSublistText]) }}</span>
|
<span class="font-normal block truncate py-2">{{ $getString('LabelLibraryFilterSublistEmpty', [selectedSublistText]) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<template v-for="item in sublistItems">
|
<template v-for="item in sublistItems">
|
||||||
<li :key="item.value" class="select-none relative px-2 cursor-pointer hover:bg-white/5" :class="`${sublist}.${item.value}` === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="option" @click="clickedSublistOption(item.value)">
|
<li :key="item.value" class="select-none relative px-2 cursor-pointer hover:bg-white/5" :class="`${sublist}.${item.value}` === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="menuitem" @click="clickedSublistOption(item.value)">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="font-normal truncate py-2 text-xs">{{ item.text }}</span>
|
<span class="font-normal truncate py-2 text-xs">{{ item.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
||||||
<button type="button" class="relative w-full h-full bg-fg border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" @click.prevent="showMenu = !showMenu">
|
<button type="button" class="relative w-full h-full bg-fg border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="menu" :aria-expanded="showMenu" @click.prevent="showMenu = !showMenu">
|
||||||
<span class="flex items-center justify-between">
|
<span class="flex items-center justify-between">
|
||||||
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
||||||
<span class="material-symbols text-lg text-yellow-400">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
<span class="material-symbols text-lg text-yellow-400" :aria-label="descending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-96 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm" role="listbox" aria-labelledby="listbox-label">
|
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-96 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm" role="menu">
|
||||||
<template v-for="item in selectItems">
|
<template v-for="item in selectItems">
|
||||||
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="option" @click="clickedOption(item.value)">
|
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="menuitem" @click="clickedOption(item.value)">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="item.value === selected" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
|
<span v-if="item.value === selected" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
|
||||||
<span class="material-symbols text-xl">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
<span class="material-symbols text-xl" :aria-label="descending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
||||||
<button type="button" class="relative w-full h-full border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none cursor-pointer" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" @click.prevent="showMenu = !showMenu">
|
<button type="button" class="relative w-full h-full border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none cursor-pointer" aria-haspopup="menu" :aria-expanded="showMenu" @click.prevent="showMenu = !showMenu">
|
||||||
<span class="flex items-center justify-between">
|
<span class="flex items-center justify-between">
|
||||||
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
||||||
<span class="material-symbols text-lg text-yellow-400">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
<span class="material-symbols text-lg text-yellow-400" :aria-label="descending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-80 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm" role="listbox" aria-labelledby="listbox-label">
|
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-80 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm" role="menu">
|
||||||
<template v-for="item in items">
|
<template v-for="item in items">
|
||||||
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="option" @click="clickedOption(item.value)">
|
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" role="menuitem" @click="clickedOption(item.value)">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="item.value === selected" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
|
<span v-if="item.value === selected" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
|
||||||
<span class="material-symbols text-xl">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
<span class="material-symbols text-xl" :aria-label="descending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ descending ? 'expand_more' : 'expand_less' }}</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default {
|
|||||||
},
|
},
|
||||||
imgSrc() {
|
imgSrc() {
|
||||||
if (!this.imagePath) return null
|
if (!this.imagePath) return null
|
||||||
return `${this.$config.routerBasePath}/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
|
return `${this.$config.routerBasePath}/api/authors/${this.authorId}/image?ts=${this.updatedAt}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ export default {
|
|||||||
|
|
||||||
var img = document.createElement('img')
|
var img = document.createElement('img')
|
||||||
img.src = src
|
img.src = src
|
||||||
|
img.alt = `${this.name}, ${this.$strings.LabelCover}`
|
||||||
|
img.ariaHidden = true
|
||||||
img.className = 'absolute top-0 left-0 w-full h-full'
|
img.className = 'absolute top-0 left-0 w-full h-full'
|
||||||
img.style.objectFit = showCoverBg ? 'contain' : 'cover'
|
img.style.objectFit = showCoverBg ? 'contain' : 'cover'
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center my-2 max-w-md">
|
||||||
|
<div class="w-1/2">
|
||||||
|
<p id="ereader-permissions-toggle">{{ $strings.LabelPermissionsCreateEreader }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2">
|
||||||
|
<ui-toggle-switch labeledBy="ereader-permissions-toggle" v-model="newUser.permissions.createEreader" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center my-2 max-w-md">
|
<div class="flex items-center my-2 max-w-md">
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<p id="explicit-content-permissions-toggle">{{ $strings.LabelPermissionsAccessExplicitContent }}</p>
|
<p id="explicit-content-permissions-toggle">{{ $strings.LabelPermissionsAccessExplicitContent }}</p>
|
||||||
@@ -354,7 +363,8 @@ export default {
|
|||||||
accessExplicitContent: type === 'admin',
|
accessExplicitContent: type === 'admin',
|
||||||
accessAllLibraries: true,
|
accessAllLibraries: true,
|
||||||
accessAllTags: true,
|
accessAllTags: true,
|
||||||
selectedTagsNotAccessible: false
|
selectedTagsNotAccessible: false,
|
||||||
|
createEreader: type === 'admin'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
@@ -387,7 +397,8 @@ export default {
|
|||||||
accessAllLibraries: true,
|
accessAllLibraries: true,
|
||||||
accessAllTags: true,
|
accessAllTags: true,
|
||||||
accessExplicitContent: false,
|
accessExplicitContent: false,
|
||||||
selectedTagsNotAccessible: false
|
selectedTagsNotAccessible: false,
|
||||||
|
createEreader: false
|
||||||
},
|
},
|
||||||
librariesAccessible: [],
|
librariesAccessible: [],
|
||||||
itemTagsSelected: []
|
itemTagsSelected: []
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrapper" class="modal modal-bg w-full h-full fixed top-0 left-0 bg-primary items-center justify-center opacity-0 hidden" :class="`z-${zIndex} bg-opacity-${bgOpacity}`">
|
<div ref="wrapper" role="dialog" aria-modal="true" class="modal modal-bg w-full h-full fixed top-0 left-0 bg-primary items-center justify-center opacity-0 hidden" :class="`z-${zIndex} bg-opacity-${bgOpacity}`">
|
||||||
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-gradient-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-gradient-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
||||||
|
|
||||||
<button class="absolute top-4 right-4 landscape:top-4 landscape:right-4 md:portrait:top-5 md:portrait:right-5 lg:top-5 lg:right-5 inline-flex text-gray-200 hover:text-white" aria-label="Close modal" @click="clickClose">
|
<button class="absolute top-4 right-4 landscape:top-4 landscape:right-4 md:portrait:top-5 md:portrait:right-5 lg:top-5 lg:right-5 inline-flex text-gray-200 hover:text-white" aria-label="Close modal" @click="clickClose">
|
||||||
<span class="material-symbols text-2xl landscape:text-2xl md:portrait:text-4xl lg:text-4xl">close</span>
|
<span class="material-symbols text-2xl landscape:text-2xl md:portrait:text-4xl lg:text-4xl">close</span>
|
||||||
</button>
|
</button>
|
||||||
<slot name="outer" />
|
<slot name="outer" />
|
||||||
<div ref="content" style="min-width: 380px; min-height: 200px; max-width: 100vw" class="relative text-white" aria-modal="true" :style="{ height: modalHeight, width: modalWidth, marginTop: contentMarginTop + 'px' }" @mousedown="mousedownModal" @mouseup="mouseupModal" v-click-outside="clickBg">
|
<div ref="content" tabindex="0" style="min-width: 380px; min-height: 200px; max-width: 100vw" class="relative text-white outline-none" :style="{ height: modalHeight, width: modalWidth, marginTop: contentMarginTop + 'px' }" @mousedown="mousedownModal" @mouseup="mouseupModal" v-click-outside="clickBg">
|
||||||
<slot />
|
<slot />
|
||||||
<div v-if="processing" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-black bg-opacity-60 rounded-lg flex items-center justify-center">
|
<div v-if="processing" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-black bg-opacity-60 rounded-lg flex items-center justify-center">
|
||||||
<ui-loading-indicator />
|
<ui-loading-indicator />
|
||||||
@@ -126,6 +126,9 @@ export default {
|
|||||||
|
|
||||||
this.$eventBus.$on('modal-hotkey', this.hotkey)
|
this.$eventBus.$on('modal-hotkey', this.hotkey)
|
||||||
this.$store.commit('setOpenModal', this.name)
|
this.$store.commit('setOpenModal', this.name)
|
||||||
|
|
||||||
|
// Set focus to the modal content
|
||||||
|
this.content.focus()
|
||||||
},
|
},
|
||||||
setHide() {
|
setHide() {
|
||||||
if (this.content) this.content.style.transform = 'scale(0)'
|
if (this.content) this.content.style.transform = 'scale(0)'
|
||||||
|
|||||||
@@ -59,12 +59,19 @@ export default {
|
|||||||
setJumpBackwardAmount(val) {
|
setJumpBackwardAmount(val) {
|
||||||
this.jumpBackwardAmount = val
|
this.jumpBackwardAmount = val
|
||||||
this.$store.dispatch('user/updateUserSettings', { jumpBackwardAmount: val })
|
this.$store.dispatch('user/updateUserSettings', { jumpBackwardAmount: val })
|
||||||
|
},
|
||||||
|
settingsUpdated() {
|
||||||
|
this.useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack')
|
||||||
|
this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount')
|
||||||
|
this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack')
|
this.settingsUpdated()
|
||||||
this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount')
|
this.$eventBus.$on('user-settings', this.settingsUpdated)
|
||||||
this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount')
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.$eventBus.$off('user-settings', this.settingsUpdated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<modals-modal v-model="show" name="changelog" :width="800" :height="'unset'">
|
<modals-modal v-model="show" name="changelog" :width="800" :height="'unset'">
|
||||||
<template #outer>
|
<template #outer>
|
||||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||||
<p class="text-3xl text-white truncate">Changelog</p>
|
<h1 class="text-3xl text-white truncate">Changelog</h1>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="px-8 py-6 w-full rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-y-scroll" style="max-height: 80vh">
|
<div class="px-8 py-6 w-full rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-y-scroll" style="max-height: 80vh">
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="custom-text" v-html="getChangelog(release)" />
|
<div class="custom-text" v-html="getChangelog(release)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="release !== releasesToShow[releasesToShow.length - 1]" class="border-b border-black-300 my-8" />
|
<div v-if="release !== releasesToShow[releasesToShow.length - 1]" :key="`${release.name}-divider`" class="border-b border-black-300 my-8" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</modals-modal>
|
</modals-modal>
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<modals-modal ref="modal" v-model="show" name="ereader-device-edit" :width="800" :height="'unset'" :processing="processing">
|
||||||
|
<template #outer>
|
||||||
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||||
|
<p class="text-3xl text-white truncate">{{ title }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<form @submit.prevent="submitForm">
|
||||||
|
<div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
|
<div class="w-full px-3 py-5 md:p-12">
|
||||||
|
<div class="flex items-center -mx-1 mb-4">
|
||||||
|
<div class="w-full md:w-1/2 px-1">
|
||||||
|
<ui-text-input-with-label ref="ereaderNameInput" v-model="newDevice.name" :disabled="processing" :label="$strings.LabelName" />
|
||||||
|
</div>
|
||||||
|
<div class="w-full md:w-1/2 px-1">
|
||||||
|
<ui-text-input-with-label ref="ereaderEmailInput" v-model="newDevice.email" :disabled="processing" :label="$strings.LabelEmail" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center pt-4">
|
||||||
|
<div class="flex-grow" />
|
||||||
|
<ui-btn color="success" type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</modals-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: Boolean,
|
||||||
|
existingDevices: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
ereaderDevice: {
|
||||||
|
type: Object,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
processing: false,
|
||||||
|
newDevice: {
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
availabilityOption: 'adminAndUp',
|
||||||
|
users: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
show: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('input', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
user() {
|
||||||
|
return this.$store.state.user.user
|
||||||
|
},
|
||||||
|
title() {
|
||||||
|
return !this.ereaderDevice ? 'Create Device' : 'Update Device'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submitForm() {
|
||||||
|
this.$refs.ereaderNameInput.blur()
|
||||||
|
this.$refs.ereaderEmailInput.blur()
|
||||||
|
|
||||||
|
if (!this.newDevice.name?.trim() || !this.newDevice.email?.trim()) {
|
||||||
|
this.$toast.error(this.$strings.ToastNameEmailRequired)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.newDevice.name = this.newDevice.name.trim()
|
||||||
|
this.newDevice.email = this.newDevice.email.trim()
|
||||||
|
|
||||||
|
// Only catches duplicate names for the current user
|
||||||
|
// Duplicates with other users caught on server side
|
||||||
|
if (!this.ereaderDevice) {
|
||||||
|
if (this.existingDevices.some((d) => d.name === this.newDevice.name)) {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.submitCreate()
|
||||||
|
} else {
|
||||||
|
if (this.ereaderDevice.name !== this.newDevice.name && this.existingDevices.some((d) => d.name === this.newDevice.name)) {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.submitUpdate()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitUpdate() {
|
||||||
|
this.processing = true
|
||||||
|
|
||||||
|
const existingDevicesWithoutThisOne = this.existingDevices.filter((d) => d.name !== this.ereaderDevice.name)
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
ereaderDevices: [
|
||||||
|
...existingDevicesWithoutThisOne,
|
||||||
|
{
|
||||||
|
...this.newDevice
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$axios
|
||||||
|
.$post(`/api/me/ereader-devices`, payload)
|
||||||
|
.then((data) => {
|
||||||
|
this.$emit('update', data.ereaderDevices)
|
||||||
|
this.show = false
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to update device', error)
|
||||||
|
if (error.response?.data?.toLowerCase().includes('duplicate')) {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
|
||||||
|
} else {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceAddFailed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitCreate() {
|
||||||
|
this.processing = true
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
ereaderDevices: [
|
||||||
|
...this.existingDevices,
|
||||||
|
{
|
||||||
|
...this.newDevice
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$axios
|
||||||
|
.$post('/api/me/ereader-devices', payload)
|
||||||
|
.then((data) => {
|
||||||
|
this.$emit('update', data.ereaderDevices || [])
|
||||||
|
this.show = false
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to add device', error)
|
||||||
|
if (error.response?.data?.toLowerCase().includes('duplicate')) {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
|
||||||
|
} else {
|
||||||
|
this.$toast.error(this.$strings.ToastDeviceAddFailed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
if (this.ereaderDevice) {
|
||||||
|
this.newDevice.name = this.ereaderDevice.name
|
||||||
|
this.newDevice.email = this.ereaderDevice.email
|
||||||
|
this.newDevice.availabilityOption = this.ereaderDevice.availabilityOption || 'specificUsers'
|
||||||
|
this.newDevice.users = this.ereaderDevice.users || [this.user.id]
|
||||||
|
} else {
|
||||||
|
this.newDevice.name = ''
|
||||||
|
this.newDevice.email = ''
|
||||||
|
this.newDevice.availabilityOption = 'specificUsers'
|
||||||
|
this.newDevice.users = [this.user.id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -111,7 +111,6 @@ export default {
|
|||||||
},
|
},
|
||||||
updateLibrary(library) {
|
updateLibrary(library) {
|
||||||
this.mapLibraryToCopy(library)
|
this.mapLibraryToCopy(library)
|
||||||
console.log('Updated library', this.libraryCopy)
|
|
||||||
},
|
},
|
||||||
getNewLibraryData() {
|
getNewLibraryData() {
|
||||||
return {
|
return {
|
||||||
@@ -128,7 +127,9 @@ export default {
|
|||||||
autoScanCronExpression: null,
|
autoScanCronExpression: null,
|
||||||
hideSingleBookSeries: false,
|
hideSingleBookSeries: false,
|
||||||
onlyShowLaterBooksInContinueSeries: false,
|
onlyShowLaterBooksInContinueSeries: false,
|
||||||
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
|
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata'],
|
||||||
|
markAsFinishedPercentComplete: null,
|
||||||
|
markAsFinishedTimeRemaining: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -236,7 +237,6 @@ export default {
|
|||||||
this.show = false
|
this.show = false
|
||||||
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
||||||
if (!this.$store.state.libraries.currentLibraryId) {
|
if (!this.$store.state.libraries.currentLibraryId) {
|
||||||
console.log('Setting initially library id', res.id)
|
|
||||||
// First library added
|
// First library added
|
||||||
this.$store.dispatch('libraries/fetch', res.id)
|
this.$store.dispatch('libraries/fetch', res.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +1,94 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
||||||
<div class="flex items-center py-3">
|
<div class="flex flex-wrap">
|
||||||
<ui-toggle-switch v-model="useSquareBookCovers" @input="formUpdated" />
|
<div class="flex items-center p-2 w-full md:w-1/2">
|
||||||
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
|
<ui-toggle-switch v-model="useSquareBookCovers" size="sm" @input="formUpdated" />
|
||||||
<p class="pl-4 text-base">
|
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
|
||||||
{{ $strings.LabelSettingsSquareBookCovers }}
|
<p class="pl-4 text-sm">
|
||||||
<span class="material-symbols icon-text text-sm">info</span>
|
{{ $strings.LabelSettingsSquareBookCovers }}
|
||||||
</p>
|
|
||||||
</ui-tooltip>
|
|
||||||
</div>
|
|
||||||
<div class="py-3">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" @input="formUpdated" />
|
|
||||||
<ui-toggle-switch v-else disabled :value="false" />
|
|
||||||
<p class="pl-4 text-base">{{ $strings.LabelSettingsEnableWatcherForLibrary }}</p>
|
|
||||||
</div>
|
|
||||||
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
|
|
||||||
</div>
|
|
||||||
<div v-if="isBookLibrary" class="flex items-center py-3">
|
|
||||||
<ui-toggle-switch v-model="audiobooksOnly" @input="formUpdated" />
|
|
||||||
<ui-tooltip :text="$strings.LabelSettingsAudiobooksOnlyHelp">
|
|
||||||
<p class="pl-4 text-base">
|
|
||||||
{{ $strings.LabelSettingsAudiobooksOnly }}
|
|
||||||
<span class="material-symbols icon-text text-sm">info</span>
|
|
||||||
</p>
|
|
||||||
</ui-tooltip>
|
|
||||||
</div>
|
|
||||||
<div v-if="isBookLibrary" class="py-3">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" @input="formUpdated" />
|
|
||||||
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="isBookLibrary" class="py-3">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<ui-toggle-switch v-model="skipMatchingMediaWithIsbn" @input="formUpdated" />
|
|
||||||
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithISBN }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="isBookLibrary" class="py-3">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<ui-toggle-switch v-model="hideSingleBookSeries" @input="formUpdated" />
|
|
||||||
<ui-tooltip :text="$strings.LabelSettingsHideSingleBookSeriesHelp">
|
|
||||||
<p class="pl-4 text-base">
|
|
||||||
{{ $strings.LabelSettingsHideSingleBookSeries }}
|
|
||||||
<span class="material-symbols icon-text text-sm">info</span>
|
<span class="material-symbols icon-text text-sm">info</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="p-2 w-full md:w-1/2">
|
||||||
<div v-if="isBookLibrary" class="py-3">
|
<div class="flex items-center">
|
||||||
<div class="flex items-center">
|
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" size="sm" @input="formUpdated" />
|
||||||
<ui-toggle-switch v-model="onlyShowLaterBooksInContinueSeries" @input="formUpdated" />
|
<ui-toggle-switch v-else disabled size="sm" :value="false" />
|
||||||
<ui-tooltip :text="$strings.LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp">
|
<p class="pl-4 text-sm">{{ $strings.LabelSettingsEnableWatcherForLibrary }}</p>
|
||||||
<p class="pl-4 text-base">
|
</div>
|
||||||
{{ $strings.LabelSettingsOnlyShowLaterBooksInContinueSeries }}
|
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="isBookLibrary" class="flex items-center p-2 w-full md:w-1/2">
|
||||||
|
<ui-toggle-switch v-model="audiobooksOnly" size="sm" @input="formUpdated" />
|
||||||
|
<ui-tooltip :text="$strings.LabelSettingsAudiobooksOnlyHelp">
|
||||||
|
<p class="pl-4 text-sm">
|
||||||
|
{{ $strings.LabelSettingsAudiobooksOnly }}
|
||||||
<span class="material-symbols icon-text text-sm">info</span>
|
<span class="material-symbols icon-text text-sm">info</span>
|
||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||||
<div v-if="isBookLibrary" class="py-3">
|
<div class="flex items-center">
|
||||||
<div class="flex items-center">
|
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" size="sm" @input="formUpdated" />
|
||||||
<ui-toggle-switch v-model="epubsAllowScriptedContent" @input="formUpdated" />
|
<p class="pl-4 text-sm">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</p>
|
||||||
<ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp">
|
</div>
|
||||||
<p class="pl-4 text-base">
|
</div>
|
||||||
{{ $strings.LabelSettingsEpubsAllowScriptedContent }}
|
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||||
<span class="material-symbols icon-text text-sm">info</span>
|
<div class="flex items-center">
|
||||||
</p>
|
<ui-toggle-switch v-model="skipMatchingMediaWithIsbn" size="sm" @input="formUpdated" />
|
||||||
</ui-tooltip>
|
<p class="pl-4 text-sm">{{ $strings.LabelSettingsSkipMatchingBooksWithISBN }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<ui-toggle-switch v-model="hideSingleBookSeries" size="sm" @input="formUpdated" />
|
||||||
|
<ui-tooltip :text="$strings.LabelSettingsHideSingleBookSeriesHelp">
|
||||||
|
<p class="pl-4 text-sm">
|
||||||
|
{{ $strings.LabelSettingsHideSingleBookSeries }}
|
||||||
|
<span class="material-symbols icon-text text-sm">info</span>
|
||||||
|
</p>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<ui-toggle-switch v-model="onlyShowLaterBooksInContinueSeries" size="sm" @input="formUpdated" />
|
||||||
|
<ui-tooltip :text="$strings.LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp">
|
||||||
|
<p class="pl-4 text-sm">
|
||||||
|
{{ $strings.LabelSettingsOnlyShowLaterBooksInContinueSeries }}
|
||||||
|
<span class="material-symbols icon-text text-sm">info</span>
|
||||||
|
</p>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<ui-toggle-switch v-model="epubsAllowScriptedContent" size="sm" @input="formUpdated" />
|
||||||
|
<ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp">
|
||||||
|
<p class="pl-4 text-sm">
|
||||||
|
{{ $strings.LabelSettingsEpubsAllowScriptedContent }}
|
||||||
|
<span class="material-symbols icon-text text-sm">info</span>
|
||||||
|
</p>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isPodcastLibrary" class="p-2 w-full md:w-1/2">
|
||||||
|
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
|
||||||
|
</div>
|
||||||
|
<div class="p-2 w-full flex items-center space-x-2 flex-wrap">
|
||||||
|
<div>
|
||||||
|
<ui-dropdown v-model="markAsFinishedWhen" :items="maskAsFinishedWhenItems" :label="$strings.LabelSettingsLibraryMarkAsFinishedWhen" small class="w-72 min-w-72 text-sm" menu-max-height="200px" @input="markAsFinishedWhenChanged" />
|
||||||
|
</div>
|
||||||
|
<div class="w-16">
|
||||||
|
<div>
|
||||||
|
<label class="px-1 text-sm font-semibold"></label>
|
||||||
|
<div class="relative">
|
||||||
|
<ui-text-input v-model="markAsFinishedValue" type="number" label="" no-spinner custom-input-class="pr-5" @input="markAsFinishedChanged" />
|
||||||
|
<div class="absolute top-0 bottom-0 right-4 flex items-center">{{ markAsFinishedWhen === 'timeRemaining' ? '' : '%' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div v-if="isPodcastLibrary" class="py-3">
|
|
||||||
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -97,7 +113,9 @@ export default {
|
|||||||
epubsAllowScriptedContent: false,
|
epubsAllowScriptedContent: false,
|
||||||
hideSingleBookSeries: false,
|
hideSingleBookSeries: false,
|
||||||
onlyShowLaterBooksInContinueSeries: false,
|
onlyShowLaterBooksInContinueSeries: false,
|
||||||
podcastSearchRegion: 'us'
|
podcastSearchRegion: 'us',
|
||||||
|
markAsFinishedWhen: 'timeRemaining',
|
||||||
|
markAsFinishedValue: 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -119,10 +137,34 @@ export default {
|
|||||||
providers() {
|
providers() {
|
||||||
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
|
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
|
||||||
return this.$store.state.scanners.providers
|
return this.$store.state.scanners.providers
|
||||||
|
},
|
||||||
|
maskAsFinishedWhenItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelSettingsLibraryMarkAsFinishedTimeRemaining,
|
||||||
|
value: 'timeRemaining'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelSettingsLibraryMarkAsFinishedPercentComplete,
|
||||||
|
value: 'percentComplete'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
markAsFinishedWhenChanged(val) {
|
||||||
|
if (val === 'percentComplete' && this.markAsFinishedValue > 100) {
|
||||||
|
this.markAsFinishedValue = 100
|
||||||
|
}
|
||||||
|
this.formUpdated()
|
||||||
|
},
|
||||||
|
markAsFinishedChanged(val) {
|
||||||
|
this.formUpdated()
|
||||||
|
},
|
||||||
getLibraryData() {
|
getLibraryData() {
|
||||||
|
let markAsFinishedTimeRemaining = this.markAsFinishedWhen === 'timeRemaining' ? Number(this.markAsFinishedValue) : null
|
||||||
|
let markAsFinishedPercentComplete = this.markAsFinishedWhen === 'percentComplete' ? Number(this.markAsFinishedValue) : null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings: {
|
settings: {
|
||||||
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
|
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
|
||||||
@@ -133,7 +175,9 @@ export default {
|
|||||||
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
|
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
|
||||||
hideSingleBookSeries: !!this.hideSingleBookSeries,
|
hideSingleBookSeries: !!this.hideSingleBookSeries,
|
||||||
onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
|
onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
|
||||||
podcastSearchRegion: this.podcastSearchRegion
|
podcastSearchRegion: this.podcastSearchRegion,
|
||||||
|
markAsFinishedTimeRemaining: markAsFinishedTimeRemaining,
|
||||||
|
markAsFinishedPercentComplete: markAsFinishedPercentComplete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -150,6 +194,11 @@ export default {
|
|||||||
this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
|
this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
|
||||||
this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
|
this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
|
||||||
this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
|
this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
|
||||||
|
this.markAsFinishedWhen = this.librarySettings.markAsFinishedTimeRemaining ? 'timeRemaining' : 'percentComplete'
|
||||||
|
if (!this.librarySettings.markAsFinishedTimeRemaining && !this.librarySettings.markAsFinishedPercentComplete) {
|
||||||
|
this.markAsFinishedWhen = 'timeRemaining'
|
||||||
|
}
|
||||||
|
this.markAsFinishedValue = this.librarySettings.markAsFinishedTimeRemaining || this.librarySettings.markAsFinishedPercentComplete || 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|||||||
@@ -18,6 +18,23 @@
|
|||||||
<p dir="auto" class="text-lg font-semibold mb-6">{{ title }}</p>
|
<p dir="auto" class="text-lg font-semibold mb-6">{{ title }}</p>
|
||||||
<div v-if="description" dir="auto" class="default-style" v-html="description" />
|
<div v-if="description" dir="auto" class="default-style" v-html="description" />
|
||||||
<p v-else class="mb-2">{{ $strings.MessageNoDescription }}</p>
|
<p v-else class="mb-2">{{ $strings.MessageNoDescription }}</p>
|
||||||
|
|
||||||
|
<div class="w-full h-px bg-white/5 my-4" />
|
||||||
|
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-grow">
|
||||||
|
<p class="font-semibold text-xs mb-1">{{ $strings.LabelFilename }}</p>
|
||||||
|
<p class="mb-2 text-xs">
|
||||||
|
{{ audioFileFilename }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<p class="font-semibold text-xs mb-1">{{ $strings.LabelSize }}</p>
|
||||||
|
<p class="mb-2 text-xs">
|
||||||
|
{{ audioFileSize }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</modals-modal>
|
</modals-modal>
|
||||||
</template>
|
</template>
|
||||||
@@ -54,7 +71,7 @@ export default {
|
|||||||
return this.episode.description || ''
|
return this.episode.description || ''
|
||||||
},
|
},
|
||||||
media() {
|
media() {
|
||||||
return this.libraryItem ? this.libraryItem.media || {} : {}
|
return this.libraryItem?.media || {}
|
||||||
},
|
},
|
||||||
mediaMetadata() {
|
mediaMetadata() {
|
||||||
return this.media.metadata || {}
|
return this.media.metadata || {}
|
||||||
@@ -65,6 +82,14 @@ export default {
|
|||||||
podcastAuthor() {
|
podcastAuthor() {
|
||||||
return this.mediaMetadata.author
|
return this.mediaMetadata.author
|
||||||
},
|
},
|
||||||
|
audioFileFilename() {
|
||||||
|
return this.episode.audioFile?.metadata?.filename || ''
|
||||||
|
},
|
||||||
|
audioFileSize() {
|
||||||
|
const size = this.episode.audioFile?.metadata?.size || 0
|
||||||
|
|
||||||
|
return this.$bytesPretty(size)
|
||||||
|
},
|
||||||
bookCoverAspectRatio() {
|
bookCoverAspectRatio() {
|
||||||
return this.$store.getters['libraries/getBookCoverAspectRatio']
|
return this.$store.getters['libraries/getBookCoverAspectRatio']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
|
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
|
||||||
|
|
||||||
<div class="w-full relative">
|
<div class="w-full relative">
|
||||||
<ui-text-input v-model="currentFeed.feedUrl" readonly />
|
<ui-text-input :value="feedUrl" readonly />
|
||||||
|
|
||||||
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(currentFeed.feedUrl)">content_copy</span>
|
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="currentFeed.meta" class="mt-5">
|
<div v-if="currentFeed.meta" class="mt-5">
|
||||||
@@ -111,8 +111,11 @@ export default {
|
|||||||
userIsAdminOrUp() {
|
userIsAdminOrUp() {
|
||||||
return this.$store.getters['user/getIsAdminOrUp']
|
return this.$store.getters['user/getIsAdminOrUp']
|
||||||
},
|
},
|
||||||
|
feedUrl() {
|
||||||
|
return this.currentFeed ? `${window.origin}${this.$config.routerBasePath}${this.currentFeed.feedUrl}` : ''
|
||||||
|
},
|
||||||
demoFeedUrl() {
|
demoFeedUrl() {
|
||||||
return `${window.origin}/feed/${this.newFeedSlug}`
|
return `${window.origin}${this.$config.routerBasePath}/feed/${this.newFeedSlug}`
|
||||||
},
|
},
|
||||||
isHttp() {
|
isHttp() {
|
||||||
return window.origin.startsWith('http://')
|
return window.origin.startsWith('http://')
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
|
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
|
||||||
|
|
||||||
<div class="w-full relative">
|
<div class="w-full relative">
|
||||||
<ui-text-input v-model="feed.feedUrl" readonly />
|
<ui-text-input :value="feedUrl" readonly />
|
||||||
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feed.feedUrl)">content_copy</span>
|
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="feed.meta" class="mt-5">
|
<div v-if="feed.meta" class="mt-5">
|
||||||
@@ -70,6 +70,9 @@ export default {
|
|||||||
},
|
},
|
||||||
_feed() {
|
_feed() {
|
||||||
return this.feed || {}
|
return this.feed || {}
|
||||||
|
},
|
||||||
|
feedUrl() {
|
||||||
|
return this.feed ? `${window.origin}${this.$config.routerBasePath}${this.feed.feedUrl}` : ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
<ui-tooltip direction="top" :text="$strings.LabelViewPlayerSettings">
|
<ui-tooltip direction="top" :text="$strings.LabelViewPlayerSettings">
|
||||||
<button :aria-label="$strings.LabelViewPlayerSettings" class="outline-none text-gray-300 mx-1 lg:mx-2 hover:text-white" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showPlayerSettings')">
|
<button :aria-label="$strings.LabelViewPlayerSettings" class="outline-none text-gray-300 mx-1 lg:mx-2 hover:text-white" @mousedown.prevent @mouseup.prevent @click.stop="showPlayerSettings">
|
||||||
<span class="material-symbols text-2xl sm:text-2.5xl">settings_slow_motion</span>
|
<span class="material-symbols text-2xl sm:text-2.5xl">settings_slow_motion</span>
|
||||||
</button>
|
</button>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
@@ -64,6 +64,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<modals-chapters-modal v-model="showChaptersModal" :current-chapter="currentChapter" :playback-rate="playbackRate" :chapters="chapters" @select="selectChapter" />
|
<modals-chapters-modal v-model="showChaptersModal" :current-chapter="currentChapter" :playback-rate="playbackRate" :chapters="chapters" @select="selectChapter" />
|
||||||
|
|
||||||
|
<modals-player-settings-modal v-model="showPlayerSettingsModal" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -96,6 +98,7 @@ export default {
|
|||||||
audioEl: null,
|
audioEl: null,
|
||||||
seekLoading: false,
|
seekLoading: false,
|
||||||
showChaptersModal: false,
|
showChaptersModal: false,
|
||||||
|
showPlayerSettingsModal: false,
|
||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
duration: 0
|
duration: 0
|
||||||
}
|
}
|
||||||
@@ -315,6 +318,9 @@ export default {
|
|||||||
if (!this.chapters.length) return
|
if (!this.chapters.length) return
|
||||||
this.showChaptersModal = !this.showChaptersModal
|
this.showChaptersModal = !this.showChaptersModal
|
||||||
},
|
},
|
||||||
|
showPlayerSettings() {
|
||||||
|
this.showPlayerSettingsModal = !this.showPlayerSettingsModal
|
||||||
|
},
|
||||||
init() {
|
init() {
|
||||||
this.playbackRate = this.$store.getters['user/getUserSetting']('playbackRate') || 1
|
this.playbackRate = this.$store.getters['user/getUserSetting']('playbackRate') || 1
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ export default {
|
|||||||
this.users = res.users.sort((a, b) => {
|
this.users = res.users.sort((a, b) => {
|
||||||
return a.createdAt - b.createdAt
|
return a.createdAt - b.createdAt
|
||||||
})
|
})
|
||||||
|
this.$emit('numUsers', this.users.length)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <p v-if="!episodes.length" class="py-4 text-center text-lg">{{ $strings.MessageNoEpisodes }}</p> -->
|
|
||||||
<div v-if="episodes.length" class="w-full py-3 mx-auto flex">
|
<div v-if="episodes.length" class="w-full py-3 mx-auto flex">
|
||||||
<form @submit.prevent="submit" class="flex flex-grow">
|
<form @submit.prevent="submit" class="flex flex-grow">
|
||||||
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="flex-grow mr-2 text-sm md:text-base" />
|
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="flex-grow mr-2 text-sm md:text-base" />
|
||||||
@@ -515,6 +514,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
filterSortChanged() {
|
filterSortChanged() {
|
||||||
|
// Save filterKey and sortKey to local storage
|
||||||
|
localStorage.setItem('podcastEpisodesFilter', this.filterKey)
|
||||||
|
localStorage.setItem('podcastEpisodesSortBy', this.sortKey + (this.sortDesc ? '-desc' : ''))
|
||||||
|
|
||||||
this.init()
|
this.init()
|
||||||
},
|
},
|
||||||
refresh() {
|
refresh() {
|
||||||
@@ -537,6 +540,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.filterKey = localStorage.getItem('podcastEpisodesFilter') || 'incomplete'
|
||||||
|
const sortBy = localStorage.getItem('podcastEpisodesSortBy') || 'publishedAt-desc'
|
||||||
|
this.sortKey = sortBy.split('-')[0]
|
||||||
|
this.sortDesc = sortBy.split('-')[1] === 'desc'
|
||||||
|
|
||||||
this.episodesCopy = this.episodes.map((ep) => ({ ...ep }))
|
this.episodesCopy = this.episodes.map((ep) => ({ ...ep }))
|
||||||
this.initListeners()
|
this.initListeners()
|
||||||
this.init()
|
this.init()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative h-9 w-9" v-click-outside="clickOutsideObj">
|
<div class="relative h-9 w-9" v-click-outside="clickOutsideObj">
|
||||||
<slot :disabled="disabled" :showMenu="showMenu" :clickShowMenu="clickShowMenu" :processing="processing">
|
<slot :disabled="disabled" :showMenu="showMenu" :clickShowMenu="clickShowMenu" :processing="processing">
|
||||||
<button v-if="!processing" type="button" :disabled="disabled" class="relative h-full w-full flex items-center justify-center shadow-sm pl-3 pr-3 text-left focus:outline-none cursor-pointer text-gray-100 hover:text-gray-200 rounded-full hover:bg-white/5" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
<button v-if="!processing" type="button" :disabled="disabled" class="relative h-full w-full flex items-center justify-center shadow-sm pl-3 pr-3 text-left focus:outline-none cursor-pointer text-gray-100 hover:text-gray-200 rounded-full hover:bg-white/5" :aria-label="$strings.LabelMore" aria-haspopup="menu" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
||||||
<span class="material-symbols text-2xl" :class="iconClass"></span>
|
<span class="material-symbols text-2xl" :class="iconClass"></span>
|
||||||
</button>
|
</button>
|
||||||
<div v-else class="h-full w-full flex items-center justify-center">
|
<div v-else class="h-full w-full flex items-center justify-center">
|
||||||
@@ -10,12 +10,12 @@
|
|||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<transition name="menu">
|
<transition name="menu">
|
||||||
<div v-show="showMenu" ref="menuWrapper" class="absolute right-0 mt-1 z-10 bg-bg border border-black-200 shadow-lg rounded-md py-1 focus:outline-none sm:text-sm" :style="{ width: menuWidth + 'px' }">
|
<div v-show="showMenu" ref="menuWrapper" role="menu" class="absolute right-0 mt-1 z-10 bg-bg border border-black-200 shadow-lg rounded-md py-1 focus:outline-none sm:text-sm" :style="{ width: menuWidth + 'px' }">
|
||||||
<template v-for="(item, index) in items">
|
<template v-for="(item, index) in items">
|
||||||
<template v-if="item.subitems">
|
<template v-if="item.subitems">
|
||||||
<div :key="index" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-default" :class="{ 'bg-white/5': mouseoverItemIndex == index }" @mouseover="mouseoverItem(index)" @mouseleave="mouseleaveItem(index)" @click.stop>
|
<button :key="index" role="menuitem" aria-haspopup="menu" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-default w-full" :class="{ 'bg-white/5': mouseoverItemIndex == index }" @mouseover="mouseoverItem(index)" @mouseleave="mouseleaveItem(index)" @click.stop>
|
||||||
<p>{{ item.text }}</p>
|
<p>{{ item.text }}</p>
|
||||||
</div>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-if="mouseoverItemIndex === index"
|
v-if="mouseoverItemIndex === index"
|
||||||
:key="`subitems-${index}`"
|
:key="`subitems-${index}`"
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
:class="openSubMenuLeft ? 'rounded-l-md' : 'rounded-r-md'"
|
:class="openSubMenuLeft ? 'rounded-l-md' : 'rounded-r-md'"
|
||||||
:style="{ left: submenuLeftPos + 'px', top: index * 28 + 'px', width: submenuWidth + 'px' }"
|
:style="{ left: submenuLeftPos + 'px', top: index * 28 + 'px', width: submenuWidth + 'px' }"
|
||||||
>
|
>
|
||||||
<div v-for="(subitem, subitemindex) in item.subitems" :key="`subitem-${subitemindex}`" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer" @click.stop="clickAction(subitem.action, subitem.data)">
|
<button v-for="(subitem, subitemindex) in item.subitems" :key="`subitem-${subitemindex}`" role="menuitem" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer w-full" @click.stop="clickAction(subitem.action, subitem.data)">
|
||||||
<p>{{ subitem.text }}</p>
|
<p>{{ subitem.text }}</p>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else :key="index" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer" @click.stop="clickAction(item.action)">
|
<button v-else :key="index" role="menuitem" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer w-full" @click.stop="clickAction(item.action)">
|
||||||
<p class="text-left">{{ item.text }}</p>
|
<p class="text-left">{{ item.text }}</p>
|
||||||
</div>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="icon-btn rounded-md flex items-center justify-center relative" @mousedown.prevent :disabled="disabled || loading" :class="className" @click="clickBtn">
|
<button :aria-label="ariaLabel" class="icon-btn rounded-md flex items-center justify-center relative" @mousedown.prevent :disabled="disabled || loading" :class="className" @click="clickBtn">
|
||||||
<div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100">
|
<div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100">
|
||||||
<svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24">
|
<svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24">
|
||||||
<path fill="currentColor" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" />
|
<path fill="currentColor" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" />
|
||||||
@@ -28,7 +28,8 @@ export default {
|
|||||||
size: {
|
size: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 9
|
default: 9
|
||||||
}
|
},
|
||||||
|
ariaLabel: String
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
class="w-10 sm:w-full relative h-full border border-white border-opacity-10 hover:border-opacity-20 rounded shadow-sm px-2 text-left text-sm cursor-pointer bg-black bg-opacity-20 text-gray-400 hover:text-gray-200"
|
class="w-10 sm:w-full relative h-full border border-white border-opacity-10 hover:border-opacity-20 rounded shadow-sm px-2 text-left text-sm cursor-pointer bg-black bg-opacity-20 text-gray-400 hover:text-gray-200"
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="menu"
|
||||||
:aria-expanded="showMenu"
|
:aria-expanded="showMenu"
|
||||||
:aria-label="$strings.ButtonLibrary + ': ' + currentLibrary.name"
|
:aria-label="$strings.ButtonLibrary + ': ' + currentLibrary.name"
|
||||||
@click.stop.prevent="clickShowMenu"
|
@click.stop.prevent="clickShowMenu"
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<transition name="menu">
|
<transition name="menu">
|
||||||
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full min-w-48 bg-primary border border-black-200 shadow-lg rounded-b-md py-1 overflow-auto focus:outline-none sm:text-sm librariesDropdownMenu" tabindex="-1" role="listbox">
|
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full min-w-48 bg-primary border border-black-200 shadow-lg rounded-b-md py-1 overflow-auto focus:outline-none sm:text-sm librariesDropdownMenu" tabindex="-1" role="menu">
|
||||||
<template v-for="library in librariesFiltered">
|
<template v-for="library in librariesFiltered">
|
||||||
<li :key="library.id" class="text-gray-400 hover:text-white relative py-2 cursor-pointer hover:bg-black-400" role="option" tabindex="0" @keydown.enter="selectLibrary(library)" @click="selectLibrary(library)">
|
<li :key="library.id" class="text-gray-400 hover:text-white relative py-2 cursor-pointer hover:bg-black-400" role="menuitem" tabindex="0" @keydown.enter="selectLibrary(library)" @click="selectLibrary(library)">
|
||||||
<div class="flex items-center px-2">
|
<div class="flex items-center px-2">
|
||||||
<ui-library-icon :icon="library.icon" class="mr-1.5" />
|
<ui-library-icon :icon="library.icon" class="mr-1.5" />
|
||||||
<span class="font-normal block truncate font-sans text-sm">{{ library.name }}</span>
|
<span class="font-normal block truncate font-sans text-sm">{{ library.name }}</span>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="icon-btn rounded-md flex items-center justify-center h-9 w-9 relative" :class="borderless ? '' : 'bg-primary border border-gray-600'" @click="clickBtn">
|
<button :aria-label="isRead ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" class="icon-btn rounded-md flex items-center justify-center h-9 w-9 relative" :class="borderless ? '' : 'bg-primary border border-gray-600'" @click="clickBtn">
|
||||||
<div class="w-5 h-5 text-white relative">
|
<div class="w-5 h-5 text-white relative">
|
||||||
<svg v-if="isRead" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(63, 181, 68)">
|
<svg v-if="isRead" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(63, 181, 68)">
|
||||||
<path d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z" />
|
<path d="M19 1H5c-1.1 0-1.99.9-1.99 2L3 15.93c0 .69.35 1.3.88 1.66L12 23l8.11-5.41c.53-.36.88-.97.88-1.66L21 3c0-1.1-.9-2-2-2zm-9 15l-5-5 1.41-1.41L10 13.17l7.59-7.59L19 7l-9 9z" />
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ export default {
|
|||||||
inputName: String,
|
inputName: String,
|
||||||
showCopy: Boolean,
|
showCopy: Boolean,
|
||||||
step: [String, Number],
|
step: [String, Number],
|
||||||
min: [String, Number]
|
min: [String, Number],
|
||||||
|
customInputClass: String
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -82,6 +83,7 @@ export default {
|
|||||||
_list.push(`py-${this.paddingY}`)
|
_list.push(`py-${this.paddingY}`)
|
||||||
if (this.noSpinner) _list.push('no-spinner')
|
if (this.noSpinner) _list.push('no-spinner')
|
||||||
if (this.textCenter) _list.push('text-center')
|
if (this.textCenter) _list.push('text-center')
|
||||||
|
if (this.customInputClass) _list.push(this.customInputClass)
|
||||||
return _list.join(' ')
|
return _list.join(' ')
|
||||||
},
|
},
|
||||||
actualType() {
|
actualType() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<button :aria-labelledby="labeledBy" role="checkbox" type="button" class="border rounded-full border-black-100 flex items-center cursor-pointer w-10 justify-start" :aria-checked="toggleValue" :class="className" @click="clickToggle">
|
<button :aria-labelledby="labeledBy" role="checkbox" type="button" class="border rounded-full border-black-100 flex items-center cursor-pointer justify-start" :style="{ width: buttonWidth + 'px' }" :aria-checked="toggleValue" :class="className" @click="clickToggle">
|
||||||
<span class="rounded-full border w-5 h-5 border-black-50 shadow transform transition-transform duration-100" :class="switchClassName"></span>
|
<span class="rounded-full border border-black-50 shadow transform transition-transform duration-100" :style="{ width: cursorHeightWidth + 'px', height: cursorHeightWidth + 'px' }" :class="switchClassName"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -19,7 +19,11 @@ export default {
|
|||||||
default: 'primary'
|
default: 'primary'
|
||||||
},
|
},
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
labeledBy: String
|
labeledBy: String,
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'md'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
toggleValue: {
|
toggleValue: {
|
||||||
@@ -37,6 +41,13 @@ export default {
|
|||||||
switchClassName() {
|
switchClassName() {
|
||||||
var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white'
|
var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white'
|
||||||
return this.toggleValue ? 'translate-x-5 ' + bgColor : bgColor
|
return this.toggleValue ? 'translate-x-5 ' + bgColor : bgColor
|
||||||
|
},
|
||||||
|
cursorHeightWidth() {
|
||||||
|
if (this.size === 'sm') return 16
|
||||||
|
return 20
|
||||||
|
},
|
||||||
|
buttonWidth() {
|
||||||
|
return this.cursorHeightWidth * 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="rounded-full py-1 bg-primary px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent>
|
<div aria-hidden="true" class="rounded-full py-1 bg-primary px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent>
|
||||||
<span class="material-symbols" :class="selectedSizeIndex === 0 ? 'text-gray-400' : 'hover:text-yellow-300 cursor-pointer'" style="font-size: 0.9rem" @mousedown.prevent @click="decreaseSize" aria-label="Decrease Cover Size" role="button"></span>
|
<span class="material-symbols" :class="selectedSizeIndex === 0 ? 'text-gray-400' : 'hover:text-yellow-300 cursor-pointer'" style="font-size: 0.9rem" @mousedown.prevent @click="decreaseSize" aria-label="Decrease Cover Size" role="button"></span>
|
||||||
<p class="px-2 font-mono" style="font-size: 1rem">{{ bookCoverWidth }}</p>
|
<p class="px-2 font-mono" style="font-size: 1rem">{{ bookCoverWidth }}</p>
|
||||||
<span class="material-symbols" :class="selectedSizeIndex === availableSizes.length - 1 ? 'text-gray-400' : 'hover:text-yellow-300 cursor-pointer'" style="font-size: 0.9rem" @mousedown.prevent @click="increaseSize" aria-label="Increase Cover Size" role="button"></span>
|
<span class="material-symbols" :class="selectedSizeIndex === availableSizes.length - 1 ? 'text-gray-400' : 'hover:text-yellow-300 cursor-pointer'" style="font-size: 0.9rem" @mousedown.prevent @click="increaseSize" aria-label="Increase Cover Size" role="button"></span>
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
<div class="flex items-center py-3e">
|
<div class="flex items-center py-3e">
|
||||||
<slot />
|
<slot />
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<button cy-id="leftScrollButton" v-if="isScrollable" class="w-8e h-8e mx-1e flex items-center justify-center rounded-full" :class="canScrollLeft ? 'hover:bg-white hover:bg-opacity-5 text-gray-300 hover:text-white' : 'text-white text-opacity-40 cursor-text'" @click="scrollLeft">
|
<button cy-id="leftScrollButton" v-if="isScrollable" :aria-label="$strings.ButtonScrollLeft" class="w-8e h-8e mx-1e flex items-center justify-center rounded-full" :class="canScrollLeft ? 'hover:bg-white hover:bg-opacity-5 text-gray-300 hover:text-white' : 'text-white text-opacity-40 cursor-text'" @click="scrollLeft">
|
||||||
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">chevron_left</span>
|
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">chevron_left</span>
|
||||||
</button>
|
</button>
|
||||||
<button cy-id="rightScrollButton" v-if="isScrollable" class="w-8e h-8e mx-1e flex items-center justify-center rounded-full" :class="canScrollRight ? 'hover:bg-white hover:bg-opacity-5 text-gray-300 hover:text-white' : 'text-white text-opacity-40 cursor-text'" @click="scrollRight">
|
<button cy-id="rightScrollButton" v-if="isScrollable" :aria-label="$strings.ButtonScrollRight" class="w-8e h-8e mx-1e flex items-center justify-center rounded-full" :class="canScrollRight ? 'hover:bg-white hover:bg-opacity-5 text-gray-300 hover:text-white' : 'text-white text-opacity-40 cursor-text'" @click="scrollRight">
|
||||||
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">chevron_right</span>
|
<span class="material-symbols" :style="{ fontSize: 1.5 + 'em' }">chevron_right</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ export default {
|
|||||||
this.showSeriesForm = true
|
this.showSeriesForm = true
|
||||||
},
|
},
|
||||||
submitSeriesForm() {
|
submitSeriesForm() {
|
||||||
console.log('submit series form', this.value, this.selectedSeries)
|
|
||||||
|
|
||||||
if (!this.selectedSeries.name) {
|
if (!this.selectedSeries.name) {
|
||||||
this.$toast.error('Must enter a series')
|
this.$toast.error('Must enter a series')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -28,10 +28,8 @@ export default {
|
|||||||
var validOtherFiles = []
|
var validOtherFiles = []
|
||||||
var ignoredFiles = []
|
var ignoredFiles = []
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
// var filetype = this.checkFileType(file.name)
|
|
||||||
if (!file.filetype) ignoredFiles.push(file)
|
if (!file.filetype) ignoredFiles.push(file)
|
||||||
else {
|
else {
|
||||||
// file.filetype = filetype
|
|
||||||
if (file.filetype === 'audio' || (file.filetype === 'ebook' && mediaType === 'book')) validItemFiles.push(file)
|
if (file.filetype === 'audio' || (file.filetype === 'ebook' && mediaType === 'book')) validItemFiles.push(file)
|
||||||
else validOtherFiles.push(file)
|
else validOtherFiles.push(file)
|
||||||
}
|
}
|
||||||
@@ -165,7 +163,7 @@ export default {
|
|||||||
|
|
||||||
var firstBookPath = Path.dirname(firstBookFile.filepath)
|
var firstBookPath = Path.dirname(firstBookFile.filepath)
|
||||||
|
|
||||||
var dirs = firstBookPath.split('/').filter(d => !!d && d !== '.')
|
var dirs = firstBookPath.split('/').filter((d) => !!d && d !== '.')
|
||||||
if (dirs.length) {
|
if (dirs.length) {
|
||||||
audiobook.title = dirs.pop()
|
audiobook.title = dirs.pop()
|
||||||
if (dirs.length > 1) {
|
if (dirs.length > 1) {
|
||||||
@@ -189,7 +187,7 @@ export default {
|
|||||||
var firstAudioFile = podcast.itemFiles[0]
|
var firstAudioFile = podcast.itemFiles[0]
|
||||||
if (!firstAudioFile.filepath) return podcast // No path
|
if (!firstAudioFile.filepath) return podcast // No path
|
||||||
var firstPath = Path.dirname(firstAudioFile.filepath)
|
var firstPath = Path.dirname(firstAudioFile.filepath)
|
||||||
var dirs = firstPath.split('/').filter(d => !!d && d !== '.')
|
var dirs = firstPath.split('/').filter((d) => !!d && d !== '.')
|
||||||
if (dirs.length) {
|
if (dirs.length) {
|
||||||
podcast.title = dirs.length > 1 ? dirs[1] : dirs[0]
|
podcast.title = dirs.length > 1 ? dirs[1] : dirs[0]
|
||||||
} else {
|
} else {
|
||||||
@@ -212,13 +210,15 @@ export default {
|
|||||||
}
|
}
|
||||||
var ignoredFiles = itemData.ignoredFiles
|
var ignoredFiles = itemData.ignoredFiles
|
||||||
var index = 1
|
var index = 1
|
||||||
var items = itemData.items.filter((ab) => {
|
var items = itemData.items
|
||||||
if (!ab.itemFiles.length) {
|
.filter((ab) => {
|
||||||
if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles)
|
if (!ab.itemFiles.length) {
|
||||||
if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles)
|
if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles)
|
||||||
}
|
if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles)
|
||||||
return ab.itemFiles.length
|
}
|
||||||
}).map(ab => this.cleanItem(ab, mediaType, index++))
|
return ab.itemFiles.length
|
||||||
|
})
|
||||||
|
.map((ab) => this.cleanItem(ab, mediaType, index++))
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
ignoredFiles
|
ignoredFiles
|
||||||
@@ -259,7 +259,7 @@ export default {
|
|||||||
|
|
||||||
otherFiles.forEach((file) => {
|
otherFiles.forEach((file) => {
|
||||||
var dir = Path.dirname(file.filepath)
|
var dir = Path.dirname(file.filepath)
|
||||||
var findItem = Object.values(itemMap).find(b => dir.startsWith(b.path))
|
var findItem = Object.values(itemMap).find((b) => dir.startsWith(b.path))
|
||||||
if (findItem) {
|
if (findItem) {
|
||||||
findItem.otherFiles.push(file)
|
findItem.otherFiles.push(file)
|
||||||
} else {
|
} else {
|
||||||
@@ -270,18 +270,18 @@ export default {
|
|||||||
var items = []
|
var items = []
|
||||||
var index = 1
|
var index = 1
|
||||||
// If book media type and all files are audio files then treat each one as an audiobook
|
// If book media type and all files are audio files then treat each one as an audiobook
|
||||||
if (itemMap[''] && !otherFiles.length && mediaType === 'book' && !itemMap[''].itemFiles.some(f => f.filetype !== 'audio')) {
|
if (itemMap[''] && !otherFiles.length && mediaType === 'book' && !itemMap[''].itemFiles.some((f) => f.filetype !== 'audio')) {
|
||||||
items = itemMap[''].itemFiles.map((audioFile) => {
|
items = itemMap[''].itemFiles.map((audioFile) => {
|
||||||
return this.cleanItem({ itemFiles: [audioFile], otherFiles: [], ignoredFiles: [] }, mediaType, index++)
|
return this.cleanItem({ itemFiles: [audioFile], otherFiles: [], ignoredFiles: [] }, mediaType, index++)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
items = Object.values(itemMap).map(i => this.cleanItem(i, mediaType, index++))
|
items = Object.values(itemMap).map((i) => this.cleanItem(i, mediaType, index++))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
ignoredFiles: ignoredFiles
|
ignoredFiles: ignoredFiles
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.15.1",
|
"version": "2.17.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.15.1",
|
"version": "2.17.5",
|
||||||
"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.15.1",
|
"version": "2.17.5",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast client",
|
"description": "Self-hosted audiobook and podcast client",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -32,9 +32,48 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showEreaderTable">
|
||||||
|
<div class="w-full h-px bg-white/10 my-4" />
|
||||||
|
|
||||||
|
<app-settings-content :header-text="$strings.HeaderEreaderDevices">
|
||||||
|
<template #header-items>
|
||||||
|
<div class="flex-grow" />
|
||||||
|
|
||||||
|
<ui-btn color="primary" small @click="addNewDeviceClick">{{ $strings.ButtonAddDevice }}</ui-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<table v-if="ereaderDevices.length" class="tracksTable mt-4">
|
||||||
|
<tr>
|
||||||
|
<th class="text-left">{{ $strings.LabelName }}</th>
|
||||||
|
<th class="text-left">{{ $strings.LabelEmail }}</th>
|
||||||
|
<th class="w-40"></th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="device in ereaderDevices" :key="device.name">
|
||||||
|
<td>
|
||||||
|
<p class="text-sm md:text-base text-gray-100">{{ device.name }}</p>
|
||||||
|
</td>
|
||||||
|
<td class="text-left">
|
||||||
|
<p class="text-sm md:text-base text-gray-100">{{ device.email }}</p>
|
||||||
|
</td>
|
||||||
|
<td class="w-40">
|
||||||
|
<div class="flex justify-end items-center h-10">
|
||||||
|
<ui-icon-btn icon="edit" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name || device.users?.length !== 1" class="mx-1" @click="editDeviceClick(device)" />
|
||||||
|
<ui-icon-btn icon="delete" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name || device.users?.length !== 1" @click="deleteDeviceClick(device)" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div v-else-if="!loading" class="text-center py-4">
|
||||||
|
<p class="text-lg text-gray-100">{{ $strings.MessageNoDevices }}</p>
|
||||||
|
</div>
|
||||||
|
</app-settings-content>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="py-4 mt-8 flex">
|
<div class="py-4 mt-8 flex">
|
||||||
<ui-btn color="primary flex items-center text-lg" @click="logout"><span class="material-symbols mr-4 icon-text">logout</span>{{ $strings.ButtonLogout }}</ui-btn>
|
<ui-btn color="primary flex items-center text-lg" @click="logout"><span class="material-symbols mr-4 icon-text">logout</span>{{ $strings.ButtonLogout }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<modals-emails-user-e-reader-device-modal v-model="showEReaderDeviceModal" :existing-devices="revisedEreaderDevices" :ereader-device="selectedEReaderDevice" @update="ereaderDevicesUpdated" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -43,11 +82,20 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
loading: false,
|
||||||
password: null,
|
password: null,
|
||||||
newPassword: null,
|
newPassword: null,
|
||||||
confirmPassword: null,
|
confirmPassword: null,
|
||||||
changingPassword: false,
|
changingPassword: false,
|
||||||
selectedLanguage: ''
|
selectedLanguage: '',
|
||||||
|
newEReaderDevice: {
|
||||||
|
name: '',
|
||||||
|
email: ''
|
||||||
|
},
|
||||||
|
ereaderDevices: [],
|
||||||
|
deletingDeviceName: null,
|
||||||
|
selectedEReaderDevice: null,
|
||||||
|
showEReaderDeviceModal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -75,6 +123,12 @@ export default {
|
|||||||
},
|
},
|
||||||
showChangePasswordForm() {
|
showChangePasswordForm() {
|
||||||
return !this.isGuest && this.isPasswordAuthEnabled
|
return !this.isGuest && this.isPasswordAuthEnabled
|
||||||
|
},
|
||||||
|
showEreaderTable() {
|
||||||
|
return this.usertype !== 'root' && this.usertype !== 'admin' && this.user.permissions?.createEreader
|
||||||
|
},
|
||||||
|
revisedEreaderDevices() {
|
||||||
|
return this.ereaderDevices.filter((device) => device.users?.length === 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -142,10 +196,52 @@ export default {
|
|||||||
this.$toast.error(this.$strings.ToastUnknownError)
|
this.$toast.error(this.$strings.ToastUnknownError)
|
||||||
this.changingPassword = false
|
this.changingPassword = false
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
addNewDeviceClick() {
|
||||||
|
this.selectedEReaderDevice = null
|
||||||
|
this.showEReaderDeviceModal = true
|
||||||
|
},
|
||||||
|
editDeviceClick(device) {
|
||||||
|
this.selectedEReaderDevice = device
|
||||||
|
this.showEReaderDeviceModal = true
|
||||||
|
},
|
||||||
|
deleteDeviceClick(device) {
|
||||||
|
const payload = {
|
||||||
|
message: this.$getString('MessageConfirmDeleteDevice', [device.name]),
|
||||||
|
callback: (confirmed) => {
|
||||||
|
if (confirmed) {
|
||||||
|
this.deleteDevice(device)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 'yesNo'
|
||||||
|
}
|
||||||
|
this.$store.commit('globals/setConfirmPrompt', payload)
|
||||||
|
},
|
||||||
|
deleteDevice(device) {
|
||||||
|
const payload = {
|
||||||
|
ereaderDevices: this.revisedEreaderDevices.filter((d) => d.name !== device.name)
|
||||||
|
}
|
||||||
|
this.deletingDeviceName = device.name
|
||||||
|
this.$axios
|
||||||
|
.$post(`/api/me/ereader-devices`, payload)
|
||||||
|
.then((data) => {
|
||||||
|
this.ereaderDevicesUpdated(data.ereaderDevices)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to delete device', error)
|
||||||
|
this.$toast.error(this.$strings.ToastRemoveFailed)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.deletingDeviceName = null
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ereaderDevicesUpdated(ereaderDevices) {
|
||||||
|
this.ereaderDevices = ereaderDevices
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.selectedLanguage = this.$languageCodes.current
|
this.selectedLanguage = this.$languageCodes.current
|
||||||
|
this.ereaderDevices = this.$store.state.libraries.ereaderDevices || []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -64,6 +64,20 @@
|
|||||||
<ui-multi-select ref="redirectUris" v-model="newAuthSettings.authOpenIDMobileRedirectURIs" :items="newAuthSettings.authOpenIDMobileRedirectURIs" :label="$strings.LabelMobileRedirectURIs" class="mb-2" :menuDisabled="true" :disabled="savingSettings" />
|
<ui-multi-select ref="redirectUris" v-model="newAuthSettings.authOpenIDMobileRedirectURIs" :items="newAuthSettings.authOpenIDMobileRedirectURIs" :label="$strings.LabelMobileRedirectURIs" class="mb-2" :menuDisabled="true" :disabled="savingSettings" />
|
||||||
<p class="sm:pl-4 text-sm text-gray-300 mb-2" v-html="$strings.LabelMobileRedirectURIsDescription" />
|
<p class="sm:pl-4 text-sm text-gray-300 mb-2" v-html="$strings.LabelMobileRedirectURIsDescription" />
|
||||||
|
|
||||||
|
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
|
||||||
|
<div class="w-44">
|
||||||
|
<ui-dropdown v-model="newAuthSettings.authOpenIDSubfolderForRedirectURLs" small :items="subfolderOptions" :label="$strings.LabelWebRedirectURLsSubfolder" :disabled="savingSettings" />
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 sm:mt-5">
|
||||||
|
<p class="sm:pl-4 text-sm text-gray-300">{{ $strings.LabelWebRedirectURLsDescription }}</p>
|
||||||
|
<p class="sm:pl-4 text-sm text-gray-300 mb-2">
|
||||||
|
<code>{{ webCallbackURL }}</code>
|
||||||
|
<br />
|
||||||
|
<code>{{ mobileAppCallbackURL }}</code>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" />
|
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" />
|
||||||
|
|
||||||
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
|
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
|
||||||
@@ -164,6 +178,27 @@ export default {
|
|||||||
value: 'username'
|
value: 'username'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
subfolderOptions() {
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
text: 'None',
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
if (this.$config.routerBasePath) {
|
||||||
|
options.push({
|
||||||
|
text: this.$config.routerBasePath,
|
||||||
|
value: this.$config.routerBasePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
webCallbackURL() {
|
||||||
|
return `https://<your.server.com>${this.newAuthSettings.authOpenIDSubfolderForRedirectURLs ? this.newAuthSettings.authOpenIDSubfolderForRedirectURLs : ''}/auth/openid/callback`
|
||||||
|
},
|
||||||
|
mobileAppCallbackURL() {
|
||||||
|
return `https://<your.server.com>${this.newAuthSettings.authOpenIDSubfolderForRedirectURLs ? this.newAuthSettings.authOpenIDSubfolderForRedirectURLs : ''}/auth/openid/mobile-redirect`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -325,7 +360,8 @@ export default {
|
|||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
this.newAuthSettings = {
|
this.newAuthSettings = {
|
||||||
...this.authSettings
|
...this.authSettings,
|
||||||
|
authOpenIDSubfolderForRedirectURLs: this.authSettings.authOpenIDSubfolderForRedirectURLs === undefined ? this.$config.routerBasePath : this.authSettings.authOpenIDSubfolderForRedirectURLs
|
||||||
}
|
}
|
||||||
this.enableLocalAuth = this.authMethods.includes('local')
|
this.enableLocalAuth = this.authMethods.includes('local')
|
||||||
this.enableOpenIDAuth = this.authMethods.includes('openid')
|
this.enableOpenIDAuth = this.authMethods.includes('openid')
|
||||||
|
|||||||
@@ -42,11 +42,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center py-2 mb-2">
|
|
||||||
<ui-toggle-switch labeledBy="settings-chromecast-support" v-model="newServerSettings.chromecastEnabled" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
|
|
||||||
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
|
<h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,6 +89,20 @@
|
|||||||
</p>
|
</p>
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pt-4">
|
||||||
|
<h2 class="font-semibold">{{ $strings.HeaderSettingsWebClient }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center py-2">
|
||||||
|
<ui-toggle-switch labeledBy="settings-chromecast-support" v-model="newServerSettings.chromecastEnabled" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
|
||||||
|
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center py-2 mb-2">
|
||||||
|
<ui-toggle-switch labeledBy="settings-allow-iframe" v-model="newServerSettings.allowIframe" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('allowIframe', val)" />
|
||||||
|
<p class="pl-4" id="settings-allow-iframe">{{ $strings.LabelSettingsAllowIframe }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
@@ -324,21 +333,21 @@ export default {
|
|||||||
},
|
},
|
||||||
updateServerSettings(payload) {
|
updateServerSettings(payload) {
|
||||||
this.updatingServerSettings = true
|
this.updatingServerSettings = true
|
||||||
this.$store
|
this.$store.dispatch('updateServerSettings', payload).then((response) => {
|
||||||
.dispatch('updateServerSettings', payload)
|
this.updatingServerSettings = false
|
||||||
.then(() => {
|
|
||||||
this.updatingServerSettings = false
|
|
||||||
|
|
||||||
if (payload.language) {
|
if (response.error) {
|
||||||
// Updating language after save allows for re-rendering
|
console.error('Failed to update server settins', response.error)
|
||||||
this.$setLanguageCode(payload.language)
|
this.$toast.error(response.error)
|
||||||
}
|
this.initServerSettings()
|
||||||
})
|
return
|
||||||
.catch((error) => {
|
}
|
||||||
console.error('Failed to update server settings', error)
|
|
||||||
this.updatingServerSettings = false
|
if (payload.language) {
|
||||||
this.$toast.error(this.$strings.ToastFailedToUpdate)
|
// Updating language after save allows for re-rendering
|
||||||
})
|
this.$setLanguageCode(payload.language)
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
initServerSettings() {
|
initServerSettings() {
|
||||||
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
|
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default {
|
|||||||
},
|
},
|
||||||
coverUrl(feed) {
|
coverUrl(feed) {
|
||||||
if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
|
if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
|
||||||
return `${feed.feedUrl}/cover`
|
return `${this.$config.routerBasePath}${feed.feedUrl}/cover`
|
||||||
},
|
},
|
||||||
async loadFeeds() {
|
async loadFeeds() {
|
||||||
const data = await this.$axios.$get(`/api/feeds`).catch((err) => {
|
const data = await this.$axios.$get(`/api/feeds`).catch((err) => {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
<ui-dropdown v-model="itemsPerPage" :items="itemsPerPageOptions" small class="w-24 mx-2" @input="updatedItemsPerPage" />
|
<ui-dropdown v-model="itemsPerPage" :items="itemsPerPageOptions" small class="w-24 mx-2" @input="updatedItemsPerPage" />
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-flex items-center">
|
<div class="inline-flex items-center">
|
||||||
<p class="text-sm mx-2">Page {{ currentPage + 1 }} of {{ numPages }}</p>
|
<p class="text-sm mx-2">{{ $getString('LabelPaginationPageXOfY', [currentPage + 1, numPages]) }}</p>
|
||||||
<ui-icon-btn icon="arrow_back_ios_new" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
|
<ui-icon-btn icon="arrow_back_ios_new" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
|
||||||
<ui-icon-btn icon="arrow_forward_ios" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
<ui-icon-btn icon="arrow_forward_ios" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
||||||
</div>
|
</div>
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
<div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
|
<div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
|
||||||
|
|
||||||
<!-- open listening sessions table -->
|
<!-- open listening sessions table -->
|
||||||
<p v-if="openListeningSessions.length" class="text-lg my-4">Open Listening Sessions</p>
|
<p v-if="openListeningSessions.length" class="text-lg my-4">{{ $strings.HeaderOpenListeningSessions }}</p>
|
||||||
<div v-if="openListeningSessions.length" class="block max-w-full">
|
<div v-if="openListeningSessions.length" class="block max-w-full">
|
||||||
<table class="userSessionsTable">
|
<table class="userSessionsTable">
|
||||||
<tr class="bg-primary bg-opacity-40">
|
<tr class="bg-primary bg-opacity-40">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<h1 class="text-xl pl-2">{{ username }}</h1>
|
<h1 class="text-xl pl-2">{{ username }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="userToken" class="flex text-xs mt-4">
|
<div v-if="userToken" class="flex text-xs mt-4">
|
||||||
<ui-text-input-with-label label="API Token" :value="userToken" readonly />
|
<ui-text-input-with-label :label="$strings.LabelApiToken" :value="userToken" readonly />
|
||||||
|
|
||||||
<div class="px-1 mt-8 cursor-pointer" @click="copyToClipboard(userToken)">
|
<div class="px-1 mt-8 cursor-pointer" @click="copyToClipboard(userToken)">
|
||||||
<span class="material-symbols pl-2 text-base">content_copy</span>
|
<span class="material-symbols pl-2 text-base">content_copy</span>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<div class="flex items-center justify-end py-1">
|
<div class="flex items-center justify-end py-1">
|
||||||
<ui-icon-btn icon="arrow_back_ios_new" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
|
<ui-icon-btn icon="arrow_back_ios_new" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
|
||||||
<p class="text-sm mx-1">Page {{ currentPage + 1 }} of {{ numPages }}</p>
|
<p class="text-sm mx-1">{{ $getString('LabelPaginationPageXOfY', [currentPage + 1, numPages]) }}</p>
|
||||||
<ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
<ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<app-settings-content :header-text="$strings.HeaderUsers">
|
<app-settings-content :header-text="$strings.HeaderUsers">
|
||||||
<template #header-items>
|
<template #header-items>
|
||||||
|
<div v-if="numUsers" class="mx-2 px-1.5 rounded-lg bg-primary/50 text-gray-300/90 text-sm inline-flex items-center justify-center">
|
||||||
|
<span>{{ numUsers }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
|
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
|
||||||
<a href="https://www.audiobookshelf.org/guides/users" target="_blank" class="inline-flex">
|
<a href="https://www.audiobookshelf.org/guides/users" target="_blank" class="inline-flex">
|
||||||
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
|
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
|
||||||
@@ -13,7 +17,7 @@
|
|||||||
<ui-btn color="primary" small @click="setShowUserModal()">{{ $strings.ButtonAddUser }}</ui-btn>
|
<ui-btn color="primary" small @click="setShowUserModal()">{{ $strings.ButtonAddUser }}</ui-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<tables-users-table class="pt-2" @edit="setShowUserModal" />
|
<tables-users-table class="pt-2" @edit="setShowUserModal" @numUsers="(count) => (numUsers = count)" />
|
||||||
</app-settings-content>
|
</app-settings-content>
|
||||||
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
|
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +33,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedAccount: null,
|
selectedAccount: null,
|
||||||
showAccountModal: false
|
showAccountModal: false,
|
||||||
|
numUsers: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
<!-- Item Cover Overlay -->
|
<!-- Item Cover Overlay -->
|
||||||
<div class="absolute top-0 left-0 w-full h-full z-10 opacity-0 group-hover:opacity-100 pointer-events-none">
|
<div class="absolute top-0 left-0 w-full h-full z-10 opacity-0 group-hover:opacity-100 pointer-events-none">
|
||||||
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
|
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
|
||||||
<div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="playItem">
|
<button class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" :aria-label="$strings.ButtonPlay" @click.stop.prevent="playItem">
|
||||||
<span class="material-symbols fill text-4xl">play_arrow</span>
|
<span class="material-symbols fill text-4xl">play_arrow</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="absolute bottom-2.5 right-2.5 z-10 material-symbols text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200 pointer-events-auto" @click="showEditCover">edit</span>
|
<button class="absolute bottom-2.5 right-2.5 z-10 material-symbols text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200 pointer-events-auto" :aria-label="$strings.ButtonEdit" @click="showEditCover">edit</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
</ui-btn>
|
</ui-btn>
|
||||||
|
|
||||||
<ui-btn v-else-if="isMissing || isInvalid" color="error" :padding-x="4" small class="flex items-center h-9 mr-2">
|
<ui-btn v-else-if="isMissing || isInvalid" color="error" :padding-x="4" small class="flex items-center h-9 mr-2">
|
||||||
<span v-show="!isStreaming" class="material-symbols text-2xl -ml-2 pr-1 text-white">error</span>
|
<span class="material-symbols text-2xl -ml-2 pr-1 text-white">error</span>
|
||||||
{{ isMissing ? $strings.LabelMissing : $strings.LabelIncomplete }}
|
{{ isMissing ? $strings.LabelMissing : $strings.LabelIncomplete }}
|
||||||
</ui-btn>
|
</ui-btn>
|
||||||
|
|
||||||
@@ -96,12 +96,12 @@
|
|||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
<ui-btn v-if="showReadButton" color="info" :padding-x="4" small class="flex items-center h-9 mr-2" @click="openEbook">
|
<ui-btn v-if="showReadButton" color="info" :padding-x="4" small class="flex items-center h-9 mr-2" @click="openEbook">
|
||||||
<span class="material-symbols text-2xl -ml-2 pr-2 text-white">auto_stories</span>
|
<span class="material-symbols text-2xl -ml-2 pr-2 text-white" aria-hidden="true">auto_stories</span>
|
||||||
{{ $strings.ButtonRead }}
|
{{ $strings.ButtonRead }}
|
||||||
</ui-btn>
|
</ui-btn>
|
||||||
|
|
||||||
<ui-tooltip v-if="userCanUpdate" :text="$strings.LabelEdit" direction="top">
|
<ui-tooltip v-if="userCanUpdate" :text="$strings.LabelEdit" direction="top">
|
||||||
<ui-icon-btn icon="" outlined class="mx-0.5" @click="editClick" />
|
<ui-icon-btn icon="" outlined class="mx-0.5" :aria-label="$strings.LabelEdit" @click="editClick" />
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
<ui-tooltip v-if="!isPodcast" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
<ui-tooltip v-if="!isPodcast" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||||
@@ -110,12 +110,12 @@
|
|||||||
|
|
||||||
<!-- Only admin or root user can download new episodes -->
|
<!-- Only admin or root user can download new episodes -->
|
||||||
<ui-tooltip v-if="isPodcast && userIsAdminOrUp" :text="$strings.LabelFindEpisodes" direction="top">
|
<ui-tooltip v-if="isPodcast && userIsAdminOrUp" :text="$strings.LabelFindEpisodes" direction="top">
|
||||||
<ui-icon-btn icon="search" class="mx-0.5" :loading="fetchingRSSFeed" outlined @click="findEpisodesClick" />
|
<ui-icon-btn icon="search" class="mx-0.5" :aria-label="$strings.LabelFindEpisodes" :loading="fetchingRSSFeed" outlined @click="findEpisodesClick" />
|
||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
|
|
||||||
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="148" @action="contextMenuAction">
|
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="148" @action="contextMenuAction">
|
||||||
<template #default="{ showMenu, clickShowMenu, disabled }">
|
<template #default="{ showMenu, clickShowMenu, disabled }">
|
||||||
<button type="button" :disabled="disabled" class="mx-0.5 icon-btn bg-primary border border-gray-600 w-9 h-9 rounded-md flex items-center justify-center relative" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
<button type="button" :disabled="disabled" class="mx-0.5 icon-btn bg-primary border border-gray-600 w-9 h-9 rounded-md flex items-center justify-center relative" aria-haspopup="listbox" :aria-expanded="showMenu" :aria-label="$strings.LabelMore" @click.stop.prevent="clickShowMenu">
|
||||||
<span class="material-symbols text-2xl"></span>
|
<span class="material-symbols text-2xl"></span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
@@ -638,6 +638,11 @@ export default {
|
|||||||
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
episodeDownloadQueueCleared(libraryItemId) {
|
||||||
|
if (libraryItemId === this.libraryItemId) {
|
||||||
|
this.episodeDownloadsQueued = []
|
||||||
|
}
|
||||||
|
},
|
||||||
rssFeedOpen(data) {
|
rssFeedOpen(data) {
|
||||||
if (data.entityId === this.libraryItemId) {
|
if (data.entityId === this.libraryItemId) {
|
||||||
console.log('RSS Feed Opened', data)
|
console.log('RSS Feed Opened', data)
|
||||||
@@ -776,6 +781,7 @@ export default {
|
|||||||
this.$root.socket.on('episode_download_queued', this.episodeDownloadQueued)
|
this.$root.socket.on('episode_download_queued', this.episodeDownloadQueued)
|
||||||
this.$root.socket.on('episode_download_started', this.episodeDownloadStarted)
|
this.$root.socket.on('episode_download_started', this.episodeDownloadStarted)
|
||||||
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
||||||
|
this.$root.socket.on('episode_download_queue_cleared', this.episodeDownloadQueueCleared)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$eventBus.$off(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
|
this.$eventBus.$off(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
|
||||||
@@ -787,6 +793,7 @@ export default {
|
|||||||
this.$root.socket.off('episode_download_queued', this.episodeDownloadQueued)
|
this.$root.socket.off('episode_download_queued', this.episodeDownloadQueued)
|
||||||
this.$root.socket.off('episode_download_started', this.episodeDownloadStarted)
|
this.$root.socket.off('episode_download_started', this.episodeDownloadStarted)
|
||||||
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
||||||
|
this.$root.socket.off('episode_download_queue_cleared', this.episodeDownloadQueueCleared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -104,9 +104,6 @@ export default {
|
|||||||
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
episodeDownloadQueueUpdated(downloadQueueDetails) {
|
|
||||||
this.episodeDownloadsQueued = downloadQueueDetails.queue.filter((q) => q.libraryId == this.libraryId)
|
|
||||||
},
|
|
||||||
async loadInitialDownloadQueue() {
|
async loadInitialDownloadQueue() {
|
||||||
this.processing = true
|
this.processing = true
|
||||||
const queuePayload = await this.$axios.$get(`/api/libraries/${this.libraryId}/episode-downloads`).catch((error) => {
|
const queuePayload = await this.$axios.$get(`/api/libraries/${this.libraryId}/episode-downloads`).catch((error) => {
|
||||||
@@ -128,7 +125,6 @@ export default {
|
|||||||
this.$root.socket.on('episode_download_queued', this.episodeDownloadQueued)
|
this.$root.socket.on('episode_download_queued', this.episodeDownloadQueued)
|
||||||
this.$root.socket.on('episode_download_started', this.episodeDownloadStarted)
|
this.$root.socket.on('episode_download_started', this.episodeDownloadStarted)
|
||||||
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
||||||
this.$root.socket.on('episode_download_queue_updated', this.episodeDownloadQueueUpdated)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -138,7 +134,6 @@ export default {
|
|||||||
this.$root.socket.off('episode_download_queued', this.episodeDownloadQueued)
|
this.$root.socket.off('episode_download_queued', this.episodeDownloadQueued)
|
||||||
this.$root.socket.off('episode_download_started', this.episodeDownloadStarted)
|
this.$root.socket.off('episode_download_started', this.episodeDownloadStarted)
|
||||||
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
||||||
this.$root.socket.off('episode_download_queue_updated', this.episodeDownloadQueueUpdated)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -126,12 +126,14 @@ export default {
|
|||||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||||
const currentTime = this.localAudioPlayer.getCurrentTime()
|
const currentTime = this.localAudioPlayer.getCurrentTime()
|
||||||
const duration = this.localAudioPlayer.getDuration()
|
const duration = this.localAudioPlayer.getDuration()
|
||||||
this.seek(Math.min(currentTime + 10, duration))
|
const jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount') || 10
|
||||||
|
this.seek(Math.min(currentTime + jumpForwardAmount, duration))
|
||||||
},
|
},
|
||||||
jumpBackward() {
|
jumpBackward() {
|
||||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||||
const currentTime = this.localAudioPlayer.getCurrentTime()
|
const currentTime = this.localAudioPlayer.getCurrentTime()
|
||||||
this.seek(Math.max(currentTime - 10, 0))
|
const jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount') || 10
|
||||||
|
this.seek(Math.max(currentTime - jumpBackwardAmount, 0))
|
||||||
},
|
},
|
||||||
setVolume(volume) {
|
setVolume(volume) {
|
||||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||||
@@ -248,6 +250,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.$store.dispatch('user/loadUserSettings')
|
||||||
|
|
||||||
this.resize()
|
this.resize()
|
||||||
window.addEventListener('resize', this.resize)
|
window.addEventListener('resize', this.resize)
|
||||||
window.addEventListener('keydown', this.keyDown)
|
window.addEventListener('keydown', this.keyDown)
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="page-wrapper" class="page p-0 sm:p-6 overflow-y-auto" :class="streamLibraryItem ? 'streaming' : ''">
|
<div id="page-wrapper" class="page p-1 sm:p-6 overflow-y-auto" :class="streamLibraryItem ? 'streaming' : ''">
|
||||||
<div class="w-full max-w-6xl mx-auto">
|
<div class="w-full max-w-6xl mx-auto">
|
||||||
<!-- Library & folder picker -->
|
<!-- Library & folder picker -->
|
||||||
<div class="flex my-6 -mx-2">
|
<div class="flex flex-wrap my-6 md:-mx-2">
|
||||||
<div class="w-1/5 px-2">
|
<div class="w-full md:w-1/5 px-2">
|
||||||
<ui-dropdown v-model="selectedLibraryId" :items="libraryItems" :label="$strings.LabelLibrary" :disabled="!!items.length" @input="libraryChanged" />
|
<ui-dropdown v-model="selectedLibraryId" :items="libraryItems" :label="$strings.LabelLibrary" :disabled="!!items.length" @input="libraryChanged" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-3/5 px-2">
|
<div class="w-full md:w-3/5 px-2">
|
||||||
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="!selectedLibraryId || !!items.length" :label="$strings.LabelFolder" />
|
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="!selectedLibraryId || !!items.length" :label="$strings.LabelFolder" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/5 px-2">
|
<div class="w-full md:w-1/5 px-2">
|
||||||
<ui-text-input-with-label :value="selectedLibraryMediaType" readonly :label="$strings.LabelMediaType" />
|
<ui-text-input-with-label :value="selectedLibraryMediaType" readonly :label="$strings.LabelMediaType" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!selectedLibraryIsPodcast" class="flex items-center mb-6">
|
<div v-if="!selectedLibraryIsPodcast" class="flex items-center mb-6 px-2 md:px-0">
|
||||||
<label class="flex cursor-pointer pt-4">
|
<label class="flex cursor-pointer pt-4">
|
||||||
<ui-toggle-switch v-model="fetchMetadata.enabled" class="inline-flex" />
|
<ui-toggle-switch v-model="fetchMetadata.enabled" class="inline-flex" />
|
||||||
<span class="pl-2 text-base">{{ $strings.LabelAutoFetchMetadata }}</span>
|
<span class="pl-2 text-base">{{ $strings.LabelAutoFetchMetadata }}</span>
|
||||||
@@ -33,13 +33,13 @@
|
|||||||
</widgets-alert>
|
</widgets-alert>
|
||||||
|
|
||||||
<!-- Picker display -->
|
<!-- Picker display -->
|
||||||
<div v-if="!items.length && !ignoredFiles.length" class="w-full mx-auto border border-white border-opacity-20 px-12 pt-12 pb-4 my-12 relative" :class="isDragging ? 'bg-primary bg-opacity-40' : 'border-dashed'">
|
<div v-if="!items.length && !ignoredFiles.length" class="w-full mx-auto border border-white border-opacity-20 px-4 md:px-12 pt-12 pb-4 my-12 relative" :class="isDragging ? 'bg-primary bg-opacity-40' : 'border-dashed'">
|
||||||
<p class="text-2xl text-center">{{ isDragging ? $strings.LabelUploaderDropFiles : $strings.LabelUploaderDragAndDrop }}</p>
|
<p class="text-2xl text-center">{{ isDragging ? $strings.LabelUploaderDropFiles : isIOS ? $strings.LabelUploaderDragAndDropFilesOnly : $strings.LabelUploaderDragAndDrop }}</p>
|
||||||
<p class="text-center text-sm my-5">{{ $strings.MessageOr }}</p>
|
<p class="text-center text-sm my-5">{{ $strings.MessageOr }}</p>
|
||||||
<div class="w-full max-w-xl mx-auto">
|
<div class="w-full max-w-xl mx-auto">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<ui-btn class="w-full mx-1" @click="openFilePicker">{{ $strings.ButtonChooseFiles }}</ui-btn>
|
<ui-btn class="w-full mx-1" @click="openFilePicker">{{ $strings.ButtonChooseFiles }}</ui-btn>
|
||||||
<ui-btn class="w-full mx-1" @click="openFolderPicker">{{ $strings.ButtonChooseAFolder }}</ui-btn>
|
<ui-btn v-if="!isIOS" class="w-full mx-1" @click="openFolderPicker">{{ $strings.ButtonChooseAFolder }} </ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-8 text-center">
|
<div class="pt-8 text-center">
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="text-sm text-white text-opacity-70">
|
<p class="text-sm text-white text-opacity-70">
|
||||||
{{ $strings.NoteUploaderFoldersWithMediaFiles }} <span v-if="selectedLibraryMediaType === 'book'">{{ $strings.NoteUploaderOnlyAudioFiles }}</span>
|
<span v-if="!isIOS">{{ $strings.NoteUploaderFoldersWithMediaFiles }}</span> <span v-if="selectedLibraryMediaType === 'book'">{{ $strings.NoteUploaderOnlyAudioFiles }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,8 +84,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input ref="fileInput" type="file" multiple :accept="inputAccept" class="hidden" @change="inputChanged" />
|
<input ref="fileInput" type="file" multiple :accept="isIOS ? '' : inputAccept" class="hidden" @change="inputChanged" />
|
||||||
<input ref="fileFolderInput" type="file" webkitdirectory multiple :accept="inputAccept" class="hidden" @change="inputChanged" />
|
<input ref="fileFolderInput" type="file" webkitdirectory multiple :accept="inputAccept" class="hidden" @change="inputChanged" v-if="!isIOS" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -127,6 +127,10 @@ export default {
|
|||||||
})
|
})
|
||||||
return extensions
|
return extensions
|
||||||
},
|
},
|
||||||
|
isIOS() {
|
||||||
|
const ua = window.navigator.userAgent
|
||||||
|
return /iPad|iPhone|iPod/.test(ua) && !window.MSStream
|
||||||
|
},
|
||||||
streamLibraryItem() {
|
streamLibraryItem() {
|
||||||
return this.$store.state.streamLibraryItem
|
return this.$store.state.streamLibraryItem
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
timeoutRetry: {
|
timeoutRetry: {
|
||||||
maxNumRetry: 4,
|
maxNumRetry: 4,
|
||||||
retryDelayMs: 0,
|
retryDelayMs: 0,
|
||||||
maxRetryDelayMs: 0,
|
maxRetryDelayMs: 0
|
||||||
},
|
},
|
||||||
errorRetry: {
|
errorRetry: {
|
||||||
maxNumRetry: 8,
|
maxNumRetry: 8,
|
||||||
@@ -160,7 +160,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
}
|
}
|
||||||
return retry
|
return retry
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +194,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
|
|
||||||
setDirectPlay() {
|
setDirectPlay() {
|
||||||
// Set initial track and track time offset
|
// Set initial track and track time offset
|
||||||
var trackIndex = this.audioTracks.findIndex(t => this.startTime >= t.startOffset && this.startTime < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => this.startTime >= t.startOffset && this.startTime < t.startOffset + t.duration)
|
||||||
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
||||||
|
|
||||||
this.loadCurrentTrack()
|
this.loadCurrentTrack()
|
||||||
@@ -270,7 +270,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
// Seeking Direct play
|
// Seeking Direct play
|
||||||
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
||||||
// Change Track
|
// Change Track
|
||||||
var trackIndex = this.audioTracks.findIndex(t => time >= t.startOffset && time < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => time >= t.startOffset && time < t.startOffset + t.duration)
|
||||||
if (trackIndex >= 0) {
|
if (trackIndex >= 0) {
|
||||||
this.startTime = time
|
this.startTime = time
|
||||||
this.currentTrackIndex = trackIndex
|
this.currentTrackIndex = trackIndex
|
||||||
@@ -293,7 +293,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
this.player.volume = volume
|
this.player.volume = volume
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
isValidDuration(duration) {
|
isValidDuration(duration) {
|
||||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||||
@@ -338,4 +337,4 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
var last = bufferedRanges[bufferedRanges.length - 1]
|
var last = bufferedRanges[bufferedRanges.length - 1]
|
||||||
return last.end
|
return last.end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,7 +297,6 @@ export default class PlayerHandler {
|
|||||||
if (listeningTimeToAdd > 20) {
|
if (listeningTimeToAdd > 20) {
|
||||||
syncData = {
|
syncData = {
|
||||||
timeListened: listeningTimeToAdd,
|
timeListened: listeningTimeToAdd,
|
||||||
duration: this.getDuration(),
|
|
||||||
currentTime: this.getCurrentTime()
|
currentTime: this.getCurrentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,7 +316,6 @@ export default class PlayerHandler {
|
|||||||
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
|
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
|
||||||
const syncData = {
|
const syncData = {
|
||||||
timeListened: listeningTimeToAdd,
|
timeListened: listeningTimeToAdd,
|
||||||
duration: this.getDuration(),
|
|
||||||
currentTime
|
currentTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const SupportedFileTypes = {
|
const SupportedFileTypes = {
|
||||||
image: ['png', 'jpg', 'jpeg', 'webp'],
|
image: ['png', 'jpg', 'jpeg', 'webp'],
|
||||||
audio: ['m4b', 'mp3', 'm4a', 'flac', 'opus', 'ogg', 'oga', 'mp4', 'aac', 'wma', 'aiff', 'wav', 'webm', 'webma', 'mka', 'awb', 'caf'],
|
audio: ['m4b', 'mp3', 'm4a', 'flac', 'opus', 'ogg', 'oga', 'mp4', 'aac', 'wma', 'aiff', 'wav', 'webm', 'webma', 'mka', 'awb', 'caf', 'mpeg', 'mpg'],
|
||||||
ebook: ['epub', 'pdf', 'mobi', 'azw3', 'cbr', 'cbz'],
|
ebook: ['epub', 'pdf', 'mobi', 'azw3', 'cbr', 'cbz'],
|
||||||
info: ['nfo'],
|
info: ['nfo'],
|
||||||
text: ['txt'],
|
text: ['txt'],
|
||||||
@@ -81,11 +81,9 @@ const Hotkeys = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Constants }
|
||||||
Constants
|
|
||||||
}
|
|
||||||
export default ({ app }, inject) => {
|
export default ({ app }, inject) => {
|
||||||
inject('constants', Constants)
|
inject('constants', Constants)
|
||||||
inject('keynames', KeyNames)
|
inject('keynames', KeyNames)
|
||||||
inject('hotkeys', Hotkeys)
|
inject('hotkeys', Hotkeys)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const defaultCode = 'en-us'
|
|||||||
const languageCodeMap = {
|
const languageCodeMap = {
|
||||||
bg: { label: 'Български', dateFnsLocale: 'bg' },
|
bg: { label: 'Български', dateFnsLocale: 'bg' },
|
||||||
bn: { label: 'বাংলা', dateFnsLocale: 'bn' },
|
bn: { label: 'বাংলা', dateFnsLocale: 'bn' },
|
||||||
|
ca: { label: 'Català', dateFnsLocale: 'ca' },
|
||||||
cs: { label: 'Čeština', dateFnsLocale: 'cs' },
|
cs: { label: 'Čeština', dateFnsLocale: 'cs' },
|
||||||
da: { label: 'Dansk', dateFnsLocale: 'da' },
|
da: { label: 'Dansk', dateFnsLocale: 'da' },
|
||||||
de: { label: 'Deutsch', dateFnsLocale: 'de' },
|
de: { label: 'Deutsch', dateFnsLocale: 'de' },
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export const getters = {
|
|||||||
const userToken = rootGetters['user/getToken']
|
const userToken = rootGetters['user/getToken']
|
||||||
const lastUpdate = libraryItem.updatedAt || Date.now()
|
const lastUpdate = libraryItem.updatedAt || Date.now()
|
||||||
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
|
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
|
||||||
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
|
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?ts=${lastUpdate}${raw ? '&raw=1' : ''}`
|
||||||
},
|
},
|
||||||
getLibraryItemCoverSrcById:
|
getLibraryItemCoverSrcById:
|
||||||
(state, getters, rootState, rootGetters) =>
|
(state, getters, rootState, rootGetters) =>
|
||||||
@@ -106,7 +106,7 @@ export const getters = {
|
|||||||
const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
||||||
if (!libraryItemId) return placeholder
|
if (!libraryItemId) return placeholder
|
||||||
const userToken = rootGetters['user/getToken']
|
const userToken = rootGetters['user/getToken']
|
||||||
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}`
|
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}`
|
||||||
},
|
},
|
||||||
getIsBatchSelectingMediaItems: (state) => {
|
getIsBatchSelectingMediaItems: (state) => {
|
||||||
return state.selectedMediaItems.length
|
return state.selectedMediaItems.length
|
||||||
|
|||||||
@@ -72,16 +72,17 @@ export const actions = {
|
|||||||
return this.$axios
|
return this.$axios
|
||||||
.$patch('/api/settings', updatePayload)
|
.$patch('/api/settings', updatePayload)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.success) {
|
if (result.serverSettings) {
|
||||||
commit('setServerSettings', result.serverSettings)
|
commit('setServerSettings', result.serverSettings)
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to update server settings', error)
|
console.error('Failed to update server settings', error)
|
||||||
return false
|
const errorMsg = error.response?.data || 'Unknown error'
|
||||||
|
return {
|
||||||
|
error: errorMsg
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
checkForUpdate({ commit }) {
|
checkForUpdate({ commit }) {
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
{
|
||||||
|
"ButtonAdd": "إضافة",
|
||||||
|
"ButtonAddChapters": "إضافة الفصول",
|
||||||
|
"ButtonAddDevice": "إضافة جهاز",
|
||||||
|
"ButtonAddLibrary": "إضافة مكتبة",
|
||||||
|
"ButtonAddPodcasts": "إضافة بودكاست",
|
||||||
|
"ButtonAddUser": "إضافة مستخدم",
|
||||||
|
"ButtonAddYourFirstLibrary": "أضف مكتبتك الأولى",
|
||||||
|
"ButtonApply": "حفظ",
|
||||||
|
"ButtonApplyChapters": "حفظ الفصول",
|
||||||
|
"ButtonAuthors": "المؤلفون",
|
||||||
|
"ButtonBack": "الرجوع",
|
||||||
|
"ButtonBrowseForFolder": "البحث عن المجلد",
|
||||||
|
"ButtonCancel": "إلغاء",
|
||||||
|
"ButtonCancelEncode": "إلغاء الترميز",
|
||||||
|
"ButtonChangeRootPassword": "تغيير كلمة المرور الرئيسية",
|
||||||
|
"ButtonCheckAndDownloadNewEpisodes": "التحقق من الحلقات الجديدة وتنزيلها",
|
||||||
|
"ButtonChooseAFolder": "اختر المجلد",
|
||||||
|
"ButtonChooseFiles": "اختر الملفات",
|
||||||
|
"ButtonClearFilter": "تصفية الفرز",
|
||||||
|
"ButtonCloseFeed": "إغلاق",
|
||||||
|
"ButtonCloseSession": "إغلاق الجلسة المفتوحة",
|
||||||
|
"ButtonCollections": "المجموعات",
|
||||||
|
"ButtonConfigureScanner": "إعدادات الماسح الضوئي",
|
||||||
|
"ButtonCreate": "إنشاء",
|
||||||
|
"ButtonCreateBackup": "إنشاء نسخة احتياطية",
|
||||||
|
"ButtonDelete": "حذف",
|
||||||
|
"ButtonDownloadQueue": "قائمة",
|
||||||
|
"ButtonEdit": "تعديل",
|
||||||
|
"ButtonEditChapters": "تعديل الفصول",
|
||||||
|
"ButtonEditPodcast": "تعديل البودكاست",
|
||||||
|
"ButtonEnable": "تفعيل",
|
||||||
|
"ButtonFireAndFail": "النار والفشل",
|
||||||
|
"ButtonFireOnTest": "حادثة إطلاق النار",
|
||||||
|
"ButtonForceReScan": "فرض إعادة المسح",
|
||||||
|
"ButtonFullPath": "المسار الكامل",
|
||||||
|
"ButtonHide": "إخفاء",
|
||||||
|
"ButtonHome": "الرئيسية",
|
||||||
|
"ButtonIssues": "مشاكل",
|
||||||
|
"ButtonJumpBackward": "اقفز للخلف",
|
||||||
|
"ButtonJumpForward": "اقفز للأمام",
|
||||||
|
"ButtonLatest": "أحدث",
|
||||||
|
"ButtonLibrary": "المكتبة",
|
||||||
|
"ButtonLogout": "تسجيل الخروج",
|
||||||
|
"ButtonLookup": "البحث",
|
||||||
|
"ButtonManageTracks": "إدارة المقاطع",
|
||||||
|
"ButtonMapChapterTitles": "مطابقة عناوين الفصول",
|
||||||
|
"ButtonMatchAllAuthors": "مطابقة كل المؤلفون",
|
||||||
|
"ButtonMatchBooks": "مطابقة الكتب",
|
||||||
|
"ButtonNevermind": "لا تهتم",
|
||||||
|
"ButtonNext": "التالي",
|
||||||
|
"ButtonNextChapter": "الفصل التالي",
|
||||||
|
"ButtonNextItemInQueue": "العنصر التالي في قائمة الانتظار",
|
||||||
|
"ButtonOk": "نعم",
|
||||||
|
"ButtonOpenFeed": "فتح التغذية",
|
||||||
|
"ButtonOpenManager": "فتح الإدارة",
|
||||||
|
"ButtonPause": "تَوَقَّف",
|
||||||
|
"ButtonPlay": "تشغيل",
|
||||||
|
"ButtonPlayAll": "تشغيل الكل",
|
||||||
|
"ButtonPlaying": "مشغل الآن",
|
||||||
|
"ButtonPlaylists": "قوائم التشغيل",
|
||||||
|
"ButtonPrevious": "سابِق",
|
||||||
|
"ButtonPreviousChapter": "الفصل السابق",
|
||||||
|
"ButtonProbeAudioFile": "فحص ملف الصوت",
|
||||||
|
"ButtonPurgeAllCache": "مسح كافة ذاكرة التخزين المؤقتة",
|
||||||
|
"ButtonPurgeItemsCache": "مسح ذاكرة التخزين المؤقتة للعناصر",
|
||||||
|
"ButtonQueueAddItem": "أضف إلى قائمة الانتظار",
|
||||||
|
"ButtonQueueRemoveItem": "إزالة من قائمة الانتظار",
|
||||||
|
"ButtonQuickEmbed": "التضمين السريع",
|
||||||
|
"ButtonQuickEmbedMetadata": "إدراج سريع للبيانات الوصفية",
|
||||||
|
"ButtonQuickMatch": "مطابقة سريعة",
|
||||||
|
"ButtonReScan": "إعادة البحث",
|
||||||
|
"ButtonRead": "اقرأ",
|
||||||
|
"ButtonReadLess": "قلص",
|
||||||
|
"ButtonReadMore": "المزيد",
|
||||||
|
"ButtonRefresh": "تحديث",
|
||||||
|
"ButtonRemove": "إزالة",
|
||||||
|
"ButtonRemoveAll": "إزالة الكل",
|
||||||
|
"ButtonRemoveAllLibraryItems": "إزالة كافة عناصر المكتبة",
|
||||||
|
"ButtonRemoveFromContinueListening": "إزالة من متابعة الاستماع",
|
||||||
|
"ButtonRemoveFromContinueReading": "إزالة من متابعة القراءة",
|
||||||
|
"ButtonRemoveSeriesFromContinueSeries": "إزالة السلسلة من استمرار السلسلة",
|
||||||
|
"ButtonReset": "إعادة ضبط",
|
||||||
|
"ButtonResetToDefault": "إعادة ضبط إلى الوضع الافتراضي",
|
||||||
|
"ButtonRestore": "إستِعادة",
|
||||||
|
"ButtonSave": "حفظ",
|
||||||
|
"ButtonSaveAndClose": "حفظ و إغلاق",
|
||||||
|
"ButtonSaveTracklist": "حفظ قائمة التشغيل",
|
||||||
|
"ButtonScan": "تَحَقُق",
|
||||||
|
"ButtonScanLibrary": "تَحَقُق من المكتبة",
|
||||||
|
"ButtonSearch": "بحث",
|
||||||
|
"ButtonSelectFolderPath": "حدد مسار المجلد",
|
||||||
|
"ButtonSeries": "سلسلة",
|
||||||
|
"ButtonSetChaptersFromTracks": "تعيين الفصول من الملفات",
|
||||||
|
"ButtonShare": "نشر",
|
||||||
|
"ButtonShiftTimes": "أوقات العمل",
|
||||||
|
"ButtonShow": "عرض",
|
||||||
|
"ButtonStartM4BEncode": "ابدأ ترميز M4B",
|
||||||
|
"ButtonStartMetadataEmbed": "ابدأ تضمين البيانات الوصفية",
|
||||||
|
"ButtonStats": "الإحصائيات",
|
||||||
|
"ButtonSubmit": "تقديم",
|
||||||
|
"ButtonTest": "اختبار",
|
||||||
|
"ButtonUnlinkOpenId": "إلغاء ربط المعرف",
|
||||||
|
"ButtonUpload": "رفع",
|
||||||
|
"ButtonUploadBackup": "تحميل النسخة الاحتياطية",
|
||||||
|
"ButtonUploadCover": "ارفق الغلاف",
|
||||||
|
"ButtonUploadOPMLFile": "رفع ملف OPML",
|
||||||
|
"ButtonUserDelete": "حذف المستخدم {0}",
|
||||||
|
"ButtonUserEdit": "تعديل المستخدم {0}",
|
||||||
|
"ButtonViewAll": "عرض الكل",
|
||||||
|
"ButtonYes": "نعم",
|
||||||
|
"ErrorUploadFetchMetadataAPI": "خطأ في جلب البيانات الوصفية",
|
||||||
|
"ErrorUploadFetchMetadataNoResults": "لم يتم العثور على البيانات الوصفية - حاول تحديث العنوان و/أو المؤلف",
|
||||||
|
"ErrorUploadLacksTitle": "يجب أن يكون له عنوان",
|
||||||
|
"HeaderAccount": "الحساب",
|
||||||
|
"HeaderAddCustomMetadataProvider": "إضافة موفر بيانات تعريفية مخصص",
|
||||||
|
"HeaderAdvanced": "متقدم",
|
||||||
|
"HeaderAppriseNotificationSettings": "إعدادات الإشعارات",
|
||||||
|
"HeaderAudioTracks": "المسارات الصوتية",
|
||||||
|
"HeaderAudiobookTools": "أدوات إدارة ملفات الكتب الصوتية",
|
||||||
|
"HeaderAuthentication": "المصادقة",
|
||||||
|
"HeaderBackups": "النسخ الاحتياطية",
|
||||||
|
"HeaderChangePassword": "تغيير كلمة المرور",
|
||||||
|
"HeaderChapters": "الفصول",
|
||||||
|
"HeaderChooseAFolder": "اختيار المجلد",
|
||||||
|
"HeaderCollection": "مجموعة",
|
||||||
|
"HeaderCollectionItems": "عناصر المجموعة",
|
||||||
|
"HeaderCover": "الغلاف",
|
||||||
|
"HeaderCurrentDownloads": "التنزيلات الجارية",
|
||||||
|
"HeaderCustomMessageOnLogin": "رسالة مخصصة عند تسجيل الدخول",
|
||||||
|
"HeaderCustomMetadataProviders": "مقدمو البيانات الوصفية المخصصة",
|
||||||
|
"HeaderDetails": "التفاصيل",
|
||||||
|
"HeaderDownloadQueue": "تنزيل قائمة الانتظار",
|
||||||
|
"HeaderEbookFiles": "ملفات الكتب الإلكترونية",
|
||||||
|
"HeaderEmail": "البريد الإلكتروني",
|
||||||
|
"HeaderEmailSettings": "إعدادات البريد الإلكتروني",
|
||||||
|
"HeaderEpisodes": "الحلقات",
|
||||||
|
"HeaderEreaderDevices": "أجهزة قراءة الكتب الإلكترونية",
|
||||||
|
"HeaderEreaderSettings": "إعدادات القارئ الإلكتروني",
|
||||||
|
"HeaderFiles": "ملفات",
|
||||||
|
"HeaderFindChapters": "البحث عن الفصول",
|
||||||
|
"HeaderIgnoredFiles": "الملفات المتجاهلة",
|
||||||
|
"HeaderItemFiles": "ملفات العنصر",
|
||||||
|
"HeaderItemMetadataUtils": "بيانات تعريف العنصر",
|
||||||
|
"HeaderLastListeningSession": "آخر جلسة استماع",
|
||||||
|
"HeaderLatestEpisodes": "أحدث الحلقات",
|
||||||
|
"HeaderLibraries": "المكتبات",
|
||||||
|
"HeaderLibraryFiles": "ملفات المكتبة",
|
||||||
|
"HeaderLibraryStats": "إحصائيات المكتبة",
|
||||||
|
"HeaderListeningSessions": "جلسات الاستماع",
|
||||||
|
"HeaderListeningStats": "جلسات الاستماع",
|
||||||
|
"HeaderLogin": "تسجيل الدخول",
|
||||||
|
"HeaderLogs": "السجلات",
|
||||||
|
"HeaderManageGenres": "إدارة الانواع",
|
||||||
|
"HeaderManageTags": "إدارة العلامات"
|
||||||
|
}
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
"ButtonPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কার করুন",
|
"ButtonPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কার করুন",
|
||||||
"ButtonQueueAddItem": "সারিতে যোগ করুন",
|
"ButtonQueueAddItem": "সারিতে যোগ করুন",
|
||||||
"ButtonQueueRemoveItem": "সারি থেকে মুছে ফেলুন",
|
"ButtonQueueRemoveItem": "সারি থেকে মুছে ফেলুন",
|
||||||
|
"ButtonQuickEmbed": "দ্রুত এম্বেড করুন",
|
||||||
"ButtonQuickEmbedMetadata": "মেটাডেটা দ্রুত এম্বেড করুন",
|
"ButtonQuickEmbedMetadata": "মেটাডেটা দ্রুত এম্বেড করুন",
|
||||||
"ButtonQuickMatch": "দ্রুত ম্যাচ",
|
"ButtonQuickMatch": "দ্রুত ম্যাচ",
|
||||||
"ButtonReScan": "পুনরায় স্ক্যান",
|
"ButtonReScan": "পুনরায় স্ক্যান",
|
||||||
@@ -162,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "বিজ্ঞপ্তি আপডেট করুন",
|
"HeaderNotificationUpdate": "বিজ্ঞপ্তি আপডেট করুন",
|
||||||
"HeaderNotifications": "বিজ্ঞপ্তি",
|
"HeaderNotifications": "বিজ্ঞপ্তি",
|
||||||
"HeaderOpenIDConnectAuthentication": "ওপেনআইডি সংযোগ প্রমাণীকরণ",
|
"HeaderOpenIDConnectAuthentication": "ওপেনআইডি সংযোগ প্রমাণীকরণ",
|
||||||
|
"HeaderOpenListeningSessions": "শোনার সেশন খুলুন",
|
||||||
"HeaderOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
"HeaderOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
||||||
"HeaderOtherFiles": "অন্যান্য ফাইল",
|
"HeaderOtherFiles": "অন্যান্য ফাইল",
|
||||||
"HeaderPasswordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
"HeaderPasswordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
||||||
@@ -179,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "{0}টি পর্ব সরান",
|
"HeaderRemoveEpisodes": "{0}টি পর্ব সরান",
|
||||||
"HeaderSavedMediaProgress": "মিডিয়া সংরক্ষণের অগ্রগতি",
|
"HeaderSavedMediaProgress": "মিডিয়া সংরক্ষণের অগ্রগতি",
|
||||||
"HeaderSchedule": "সময়সূচী",
|
"HeaderSchedule": "সময়সূচী",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "স্বয়ংক্রিয় পর্ব ডাউনলোডের সময়সূচী নির্ধারন করুন",
|
||||||
"HeaderScheduleLibraryScans": "স্বয়ংক্রিয় লাইব্রেরি স্ক্যানের সময়সূচী",
|
"HeaderScheduleLibraryScans": "স্বয়ংক্রিয় লাইব্রেরি স্ক্যানের সময়সূচী",
|
||||||
"HeaderSession": "সেশন",
|
"HeaderSession": "সেশন",
|
||||||
"HeaderSetBackupSchedule": "ব্যাকআপ সময়সূচী সেট করুন",
|
"HeaderSetBackupSchedule": "ব্যাকআপ সময়সূচী সেট করুন",
|
||||||
@@ -224,7 +227,11 @@
|
|||||||
"LabelAllUsersExcludingGuests": "অতিথি ব্যতীত সকল ব্যবহারকারী",
|
"LabelAllUsersExcludingGuests": "অতিথি ব্যতীত সকল ব্যবহারকারী",
|
||||||
"LabelAllUsersIncludingGuests": "অতিথি সহ সকল ব্যবহারকারী",
|
"LabelAllUsersIncludingGuests": "অতিথি সহ সকল ব্যবহারকারী",
|
||||||
"LabelAlreadyInYourLibrary": "ইতিমধ্যেই আপনার লাইব্রেরিতে রয়েছে",
|
"LabelAlreadyInYourLibrary": "ইতিমধ্যেই আপনার লাইব্রেরিতে রয়েছে",
|
||||||
|
"LabelApiToken": "API টোকেন",
|
||||||
"LabelAppend": "সংযোজন",
|
"LabelAppend": "সংযোজন",
|
||||||
|
"LabelAudioBitrate": "অডিও বিটরেট (যেমন- 128k)",
|
||||||
|
"LabelAudioChannels": "অডিও চ্যানেল (১ বা ২)",
|
||||||
|
"LabelAudioCodec": "অডিও কোডেক",
|
||||||
"LabelAuthor": "লেখক",
|
"LabelAuthor": "লেখক",
|
||||||
"LabelAuthorFirstLast": "লেখক (প্রথম শেষ)",
|
"LabelAuthorFirstLast": "লেখক (প্রথম শেষ)",
|
||||||
"LabelAuthorLastFirst": "লেখক (শেষ, প্রথম)",
|
"LabelAuthorLastFirst": "লেখক (শেষ, প্রথম)",
|
||||||
@@ -237,6 +244,7 @@
|
|||||||
"LabelAutoRegister": "স্বয়ংক্রিয় নিবন্ধন",
|
"LabelAutoRegister": "স্বয়ংক্রিয় নিবন্ধন",
|
||||||
"LabelAutoRegisterDescription": "লগ ইন করার পর স্বয়ংক্রিয়ভাবে নতুন ব্যবহারকারী তৈরি করুন",
|
"LabelAutoRegisterDescription": "লগ ইন করার পর স্বয়ংক্রিয়ভাবে নতুন ব্যবহারকারী তৈরি করুন",
|
||||||
"LabelBackToUser": "ব্যবহারকারীর কাছে ফিরে যান",
|
"LabelBackToUser": "ব্যবহারকারীর কাছে ফিরে যান",
|
||||||
|
"LabelBackupAudioFiles": "অডিও ফাইলগুলো ব্যাকআপ",
|
||||||
"LabelBackupLocation": "ব্যাকআপ অবস্থান",
|
"LabelBackupLocation": "ব্যাকআপ অবস্থান",
|
||||||
"LabelBackupsEnableAutomaticBackups": "স্বয়ংক্রিয় ব্যাকআপ সক্ষম করুন",
|
"LabelBackupsEnableAutomaticBackups": "স্বয়ংক্রিয় ব্যাকআপ সক্ষম করুন",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "ব্যাকআপগুলি /মেটাডাটা/ব্যাকআপে সংরক্ষিত",
|
"LabelBackupsEnableAutomaticBackupsHelp": "ব্যাকআপগুলি /মেটাডাটা/ব্যাকআপে সংরক্ষিত",
|
||||||
@@ -245,15 +253,18 @@
|
|||||||
"LabelBackupsNumberToKeep": "ব্যাকআপের সংখ্যা রাখুন",
|
"LabelBackupsNumberToKeep": "ব্যাকআপের সংখ্যা রাখুন",
|
||||||
"LabelBackupsNumberToKeepHelp": "এক সময়ে শুধুমাত্র ১ টি ব্যাকআপ সরানো হবে তাই যদি আপনার কাছে ইতিমধ্যে এর চেয়ে বেশি ব্যাকআপ থাকে তাহলে আপনাকে ম্যানুয়ালি সেগুলি সরিয়ে ফেলতে হবে।",
|
"LabelBackupsNumberToKeepHelp": "এক সময়ে শুধুমাত্র ১ টি ব্যাকআপ সরানো হবে তাই যদি আপনার কাছে ইতিমধ্যে এর চেয়ে বেশি ব্যাকআপ থাকে তাহলে আপনাকে ম্যানুয়ালি সেগুলি সরিয়ে ফেলতে হবে।",
|
||||||
"LabelBitrate": "বিটরেট",
|
"LabelBitrate": "বিটরেট",
|
||||||
|
"LabelBonus": "উপরিলাভ",
|
||||||
"LabelBooks": "বইগুলো",
|
"LabelBooks": "বইগুলো",
|
||||||
"LabelButtonText": "ঘর পাঠ্য",
|
"LabelButtonText": "ঘর পাঠ্য",
|
||||||
"LabelByAuthor": "দ্বারা {0}",
|
"LabelByAuthor": "দ্বারা {0}",
|
||||||
"LabelChangePassword": "পাসওয়ার্ড পরিবর্তন করুন",
|
"LabelChangePassword": "পাসওয়ার্ড পরিবর্তন করুন",
|
||||||
"LabelChannels": "চ্যানেল",
|
"LabelChannels": "চ্যানেল",
|
||||||
|
"LabelChapterCount": "{0} অধ্যায়",
|
||||||
"LabelChapterTitle": "অধ্যায়ের শিরোনাম",
|
"LabelChapterTitle": "অধ্যায়ের শিরোনাম",
|
||||||
"LabelChapters": "অধ্যায়",
|
"LabelChapters": "অধ্যায়",
|
||||||
"LabelChaptersFound": "অধ্যায় পাওয়া গেছে",
|
"LabelChaptersFound": "অধ্যায় পাওয়া গেছে",
|
||||||
"LabelClickForMoreInfo": "আরো তথ্যের জন্য ক্লিক করুন",
|
"LabelClickForMoreInfo": "আরো তথ্যের জন্য ক্লিক করুন",
|
||||||
|
"LabelClickToUseCurrentValue": "বর্তমান মান ব্যবহার করতে ক্লিক করুন",
|
||||||
"LabelClosePlayer": "প্লেয়ার বন্ধ করুন",
|
"LabelClosePlayer": "প্লেয়ার বন্ধ করুন",
|
||||||
"LabelCodec": "কোডেক",
|
"LabelCodec": "কোডেক",
|
||||||
"LabelCollapseSeries": "সিরিজ সঙ্কুচিত করুন",
|
"LabelCollapseSeries": "সিরিজ সঙ্কুচিত করুন",
|
||||||
@@ -303,12 +314,25 @@
|
|||||||
"LabelEmailSettingsTestAddress": "পরীক্ষার ঠিকানা",
|
"LabelEmailSettingsTestAddress": "পরীক্ষার ঠিকানা",
|
||||||
"LabelEmbeddedCover": "এম্বেডেড কভার",
|
"LabelEmbeddedCover": "এম্বেডেড কভার",
|
||||||
"LabelEnable": "সক্ষম করুন",
|
"LabelEnable": "সক্ষম করুন",
|
||||||
|
"LabelEncodingBackupLocation": "আপনার আসল অডিও ফাইলগুলোর একটি ব্যাকআপ এখানে সংরক্ষণ করা হবে:",
|
||||||
|
"LabelEncodingChaptersNotEmbedded": "মাল্টি-ট্র্যাক অডিওবুকগুলোতে অধ্যায় এম্বেড করা হয় না।",
|
||||||
|
"LabelEncodingClearItemCache": "পর্যায়ক্রমে আইটেম ক্যাশে পরিষ্কার করতে ভুলবেন না।",
|
||||||
|
"LabelEncodingFinishedM4B": "সমাপ্ত হওয়া M4B-গুলো আপনার অডিওবুক ফোল্ডারে এখানে রাখা হবে:",
|
||||||
|
"LabelEncodingInfoEmbedded": "আপনার অডিওবুক ফোল্ডারের ভিতরে অডিও ট্র্যাকগুলোতে মেটাডেটা এমবেড করা হবে।",
|
||||||
|
"LabelEncodingStartedNavigation": "একবার টাস্ক শুরু হলে আপনি এই পৃষ্ঠা থেকে অন্যত্র যেতে পারেন।",
|
||||||
|
"LabelEncodingTimeWarning": "এনকোডিং ৩০ মিনিট পর্যন্ত সময় নিতে পারে।",
|
||||||
|
"LabelEncodingWarningAdvancedSettings": "সতর্কতা: এই সেটিংস আপডেট করবেন না, যদি না আপনি ffmpeg এনকোডিং বিকল্পগুলোর সাথে পরিচিত হন।",
|
||||||
|
"LabelEncodingWatcherDisabled": "আপনার যদি পর্যবেক্ষক অক্ষম থাকে তবে আপনাকে পরে এই অডিওবুকটি পুনরায় স্ক্যান করতে হবে।",
|
||||||
"LabelEnd": "সমাপ্ত",
|
"LabelEnd": "সমাপ্ত",
|
||||||
"LabelEndOfChapter": "অধ্যায়ের সমাপ্তি",
|
"LabelEndOfChapter": "অধ্যায়ের সমাপ্তি",
|
||||||
"LabelEpisode": "পর্ব",
|
"LabelEpisode": "পর্ব",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "পর্বটি আরএসএস ফিডের সাথে সংযুক্ত করা হয়নি",
|
||||||
|
"LabelEpisodeNumber": "পর্ব #{0}",
|
||||||
"LabelEpisodeTitle": "পর্বের শিরোনাম",
|
"LabelEpisodeTitle": "পর্বের শিরোনাম",
|
||||||
"LabelEpisodeType": "পর্বের ধরন",
|
"LabelEpisodeType": "পর্বের ধরন",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "আরএসএস ফিড থেকে পর্ব URL",
|
||||||
"LabelEpisodes": "পর্বগুলো",
|
"LabelEpisodes": "পর্বগুলো",
|
||||||
|
"LabelEpisodic": "প্রাসঙ্গিক",
|
||||||
"LabelExample": "উদাহরণ",
|
"LabelExample": "উদাহরণ",
|
||||||
"LabelExpandSeries": "সিরিজ প্রসারিত করুন",
|
"LabelExpandSeries": "সিরিজ প্রসারিত করুন",
|
||||||
"LabelExpandSubSeries": "সাব সিরিজ প্রসারিত করুন",
|
"LabelExpandSubSeries": "সাব সিরিজ প্রসারিত করুন",
|
||||||
@@ -336,6 +360,7 @@
|
|||||||
"LabelFontScale": "ফন্ট স্কেল",
|
"LabelFontScale": "ফন্ট স্কেল",
|
||||||
"LabelFontStrikethrough": "অবচ্ছেদন রেখা",
|
"LabelFontStrikethrough": "অবচ্ছেদন রেখা",
|
||||||
"LabelFormat": "ফরম্যাট",
|
"LabelFormat": "ফরম্যাট",
|
||||||
|
"LabelFull": "পূর্ণ",
|
||||||
"LabelGenre": "ঘরানা",
|
"LabelGenre": "ঘরানা",
|
||||||
"LabelGenres": "ঘরানাগুলো",
|
"LabelGenres": "ঘরানাগুলো",
|
||||||
"LabelHardDeleteFile": "জোরপূর্বক ফাইল মুছে ফেলুন",
|
"LabelHardDeleteFile": "জোরপূর্বক ফাইল মুছে ফেলুন",
|
||||||
@@ -391,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "সর্বনিম্ন অগ্রাধিকার",
|
"LabelLowestPriority": "সর্বনিম্ন অগ্রাধিকার",
|
||||||
"LabelMatchExistingUsersBy": "বিদ্যমান ব্যবহারকারীদের দ্বারা মিলিত করুন",
|
"LabelMatchExistingUsersBy": "বিদ্যমান ব্যবহারকারীদের দ্বারা মিলিত করুন",
|
||||||
"LabelMatchExistingUsersByDescription": "বিদ্যমান ব্যবহারকারীদের সংযোগ করার জন্য ব্যবহৃত হয়। একবার সংযুক্ত হলে, ব্যবহারকারীদের আপনার SSO প্রদানকারীর থেকে একটি অনন্য আইডি দ্বারা মিলিত হবে",
|
"LabelMatchExistingUsersByDescription": "বিদ্যমান ব্যবহারকারীদের সংযোগ করার জন্য ব্যবহৃত হয়। একবার সংযুক্ত হলে, ব্যবহারকারীদের আপনার SSO প্রদানকারীর থেকে একটি অনন্য আইডি দ্বারা মিলিত হবে",
|
||||||
|
"LabelMaxEpisodesToDownload": "সর্বাধিক # টি পর্ব ডাউনলোড করা হবে। অসীমের জন্য 0 ব্যবহার করুন।",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "প্রতি কিস্তিতে সর্বাধিক # টি নতুন পর্ব ডাউনলোড করা হবে",
|
||||||
|
"LabelMaxEpisodesToKeep": "সর্বোচ্চ # টি পর্ব রাখা হবে",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "০ কোন সর্বোচ্চ সীমা সেট করে না। একটি নতুন পর্ব স্বয়ংক্রিয়-ডাউনলোড হওয়ার পরে আপনার যদি X-এর বেশি পর্ব থাকে তবে এটি সবচেয়ে পুরানো পর্বটি মুছে ফেলবে। এটি প্রতি নতুন ডাউনলোডের জন্য শুধুমাত্র ১ টি পর্ব মুছে ফেলবে।",
|
||||||
"LabelMediaPlayer": "মিডিয়া প্লেয়ার",
|
"LabelMediaPlayer": "মিডিয়া প্লেয়ার",
|
||||||
"LabelMediaType": "মিডিয়ার ধরন",
|
"LabelMediaType": "মিডিয়ার ধরন",
|
||||||
"LabelMetaTag": "মেটা ট্যাগ",
|
"LabelMetaTag": "মেটা ট্যাগ",
|
||||||
@@ -436,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "ওপেনআইডি দাবির নাম যাতে ব্যবহারকারীর গোষ্ঠীর একটি তালিকা থাকে। সাধারণত <code>গ্রুপ</code> হিসাবে উল্লেখ করা হয়। <b>কনফিগার করা থাকলে</b>, অ্যাপ্লিকেশনটি স্বয়ংক্রিয়ভাবে এর উপর ভিত্তি করে ব্যবহারকারীর গোষ্ঠীর সদস্যপদ নির্ধারণ করবে, শর্ত এই যে এই গোষ্ঠীগুলি কেস-অসংবেদনশীলভাবে দাবিতে 'অ্যাডমিন', 'ব্যবহারকারী' বা 'অতিথি' নাম দেওয়া হয়৷ দাবিতে একটি তালিকা থাকা উচিত এবং যদি একজন ব্যবহারকারী একাধিক গোষ্ঠীর অন্তর্গত হয় তবে অ্যাপ্লিকেশনটি বরাদ্দ করবে সর্বোচ্চ স্তরের অ্যাক্সেসের সাথে সঙ্গতিপূর্ণ ভূমিকা৷ যদি কোনও গোষ্ঠীর সাথে মেলে না, তবে অ্যাক্সেস অস্বীকার করা হবে।",
|
"LabelOpenIDGroupClaimDescription": "ওপেনআইডি দাবির নাম যাতে ব্যবহারকারীর গোষ্ঠীর একটি তালিকা থাকে। সাধারণত <code>গ্রুপ</code> হিসাবে উল্লেখ করা হয়। <b>কনফিগার করা থাকলে</b>, অ্যাপ্লিকেশনটি স্বয়ংক্রিয়ভাবে এর উপর ভিত্তি করে ব্যবহারকারীর গোষ্ঠীর সদস্যপদ নির্ধারণ করবে, শর্ত এই যে এই গোষ্ঠীগুলি কেস-অসংবেদনশীলভাবে দাবিতে 'অ্যাডমিন', 'ব্যবহারকারী' বা 'অতিথি' নাম দেওয়া হয়৷ দাবিতে একটি তালিকা থাকা উচিত এবং যদি একজন ব্যবহারকারী একাধিক গোষ্ঠীর অন্তর্গত হয় তবে অ্যাপ্লিকেশনটি বরাদ্দ করবে সর্বোচ্চ স্তরের অ্যাক্সেসের সাথে সঙ্গতিপূর্ণ ভূমিকা৷ যদি কোনও গোষ্ঠীর সাথে মেলে না, তবে অ্যাক্সেস অস্বীকার করা হবে।",
|
||||||
"LabelOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
"LabelOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
||||||
"LabelOverwrite": "পুনঃলিখিত",
|
"LabelOverwrite": "পুনঃলিখিত",
|
||||||
|
"LabelPaginationPageXOfY": "{1} টির মধ্যে {0} পৃষ্ঠা",
|
||||||
"LabelPassword": "পাসওয়ার্ড",
|
"LabelPassword": "পাসওয়ার্ড",
|
||||||
"LabelPath": "পথ",
|
"LabelPath": "পথ",
|
||||||
"LabelPermanent": "স্থায়ী",
|
"LabelPermanent": "স্থায়ী",
|
||||||
"LabelPermissionsAccessAllLibraries": "সমস্ত লাইব্রেরি অ্যাক্সেস করতে পারবে",
|
"LabelPermissionsAccessAllLibraries": "সমস্ত লাইব্রেরি অ্যাক্সেস করতে পারবে",
|
||||||
"LabelPermissionsAccessAllTags": "সমস্ত ট্যাগ অ্যাক্সেস করতে পারবে",
|
"LabelPermissionsAccessAllTags": "সমস্ত ট্যাগ অ্যাক্সেস করতে পারবে",
|
||||||
"LabelPermissionsAccessExplicitContent": "স্পষ্ট বিষয়বস্তু অ্যাক্সেস করতে পারে",
|
"LabelPermissionsAccessExplicitContent": "স্পষ্ট বিষয়বস্তু অ্যাক্সেস করতে পারে",
|
||||||
|
"LabelPermissionsCreateEreader": "ইরিডার তৈরি করতে পারেন",
|
||||||
"LabelPermissionsDelete": "মুছে দিতে পারবে",
|
"LabelPermissionsDelete": "মুছে দিতে পারবে",
|
||||||
"LabelPermissionsDownload": "ডাউনলোড করতে পারবে",
|
"LabelPermissionsDownload": "ডাউনলোড করতে পারবে",
|
||||||
"LabelPermissionsUpdate": "আপডেট করতে পারবে",
|
"LabelPermissionsUpdate": "আপডেট করতে পারবে",
|
||||||
@@ -465,6 +496,8 @@
|
|||||||
"LabelPubDate": "প্রকাশের তারিখ",
|
"LabelPubDate": "প্রকাশের তারিখ",
|
||||||
"LabelPublishYear": "প্রকাশের বছর",
|
"LabelPublishYear": "প্রকাশের বছর",
|
||||||
"LabelPublishedDate": "প্রকাশিত {0}",
|
"LabelPublishedDate": "প্রকাশিত {0}",
|
||||||
|
"LabelPublishedDecade": "প্রকাশনার দশক",
|
||||||
|
"LabelPublishedDecades": "প্রকাশনার দশকগুলো",
|
||||||
"LabelPublisher": "প্রকাশক",
|
"LabelPublisher": "প্রকাশক",
|
||||||
"LabelPublishers": "প্রকাশকরা",
|
"LabelPublishers": "প্রকাশকরা",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "কাস্টম মালিকের ইমেইল",
|
"LabelRSSFeedCustomOwnerEmail": "কাস্টম মালিকের ইমেইল",
|
||||||
@@ -484,21 +517,28 @@
|
|||||||
"LabelRedo": "পুনরায় করুন",
|
"LabelRedo": "পুনরায় করুন",
|
||||||
"LabelRegion": "অঞ্চল",
|
"LabelRegion": "অঞ্চল",
|
||||||
"LabelReleaseDate": "উন্মোচনের তারিখ",
|
"LabelReleaseDate": "উন্মোচনের তারিখ",
|
||||||
|
"LabelRemoveAllMetadataAbs": "সমস্ত metadata.abs ফাইল সরান",
|
||||||
|
"LabelRemoveAllMetadataJson": "সমস্ত metadata.json ফাইল সরান",
|
||||||
"LabelRemoveCover": "কভার সরান",
|
"LabelRemoveCover": "কভার সরান",
|
||||||
|
"LabelRemoveMetadataFile": "লাইব্রেরি আইটেম ফোল্ডারে মেটাডেটা ফাইল সরান",
|
||||||
|
"LabelRemoveMetadataFileHelp": "আপনার {0} ফোল্ডারের সমস্ত metadata.json এবং metadata.abs ফাইলগুলি সরান।",
|
||||||
"LabelRowsPerPage": "প্রতি পৃষ্ঠায় সারি",
|
"LabelRowsPerPage": "প্রতি পৃষ্ঠায় সারি",
|
||||||
"LabelSearchTerm": "অনুসন্ধান শব্দ",
|
"LabelSearchTerm": "অনুসন্ধান শব্দ",
|
||||||
"LabelSearchTitle": "অনুসন্ধান শিরোনাম",
|
"LabelSearchTitle": "অনুসন্ধান শিরোনাম",
|
||||||
"LabelSearchTitleOrASIN": "অনুসন্ধান শিরোনাম বা ASIN",
|
"LabelSearchTitleOrASIN": "অনুসন্ধান শিরোনাম বা ASIN",
|
||||||
"LabelSeason": "সেশন",
|
"LabelSeason": "সেশন",
|
||||||
|
"LabelSeasonNumber": "মরসুম #{0}",
|
||||||
"LabelSelectAll": "সব নির্বাচন করুন",
|
"LabelSelectAll": "সব নির্বাচন করুন",
|
||||||
"LabelSelectAllEpisodes": "সমস্ত পর্ব নির্বাচন করুন",
|
"LabelSelectAllEpisodes": "সমস্ত পর্ব নির্বাচন করুন",
|
||||||
"LabelSelectEpisodesShowing": "দেখানো {0}টি পর্ব নির্বাচন করুন",
|
"LabelSelectEpisodesShowing": "দেখানো {0}টি পর্ব নির্বাচন করুন",
|
||||||
"LabelSelectUsers": "ব্যবহারকারী নির্বাচন করুন",
|
"LabelSelectUsers": "ব্যবহারকারী নির্বাচন করুন",
|
||||||
"LabelSendEbookToDevice": "ই-বই পাঠান...",
|
"LabelSendEbookToDevice": "ই-বই পাঠান...",
|
||||||
"LabelSequence": "ক্রম",
|
"LabelSequence": "ক্রম",
|
||||||
|
"LabelSerial": "ধারাবাহিক",
|
||||||
"LabelSeries": "সিরিজ",
|
"LabelSeries": "সিরিজ",
|
||||||
"LabelSeriesName": "সিরিজের নাম",
|
"LabelSeriesName": "সিরিজের নাম",
|
||||||
"LabelSeriesProgress": "সিরিজের অগ্রগতি",
|
"LabelSeriesProgress": "সিরিজের অগ্রগতি",
|
||||||
|
"LabelServerLogLevel": "সার্ভার লগ লেভেল",
|
||||||
"LabelServerYearReview": "সার্ভারের বাৎসরিক পর্যালোচনা ({0})",
|
"LabelServerYearReview": "সার্ভারের বাৎসরিক পর্যালোচনা ({0})",
|
||||||
"LabelSetEbookAsPrimary": "প্রাথমিক হিসাবে সেট করুন",
|
"LabelSetEbookAsPrimary": "প্রাথমিক হিসাবে সেট করুন",
|
||||||
"LabelSetEbookAsSupplementary": "পরিপূরক হিসেবে সেট করুন",
|
"LabelSetEbookAsSupplementary": "পরিপূরক হিসেবে সেট করুন",
|
||||||
@@ -523,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "যে সিরিজগুলোতে একটি বই আছে সেগুলো সিরিজের পাতা এবং নীড় পেজের তাক থেকে লুকিয়ে রাখা হবে।",
|
"LabelSettingsHideSingleBookSeriesHelp": "যে সিরিজগুলোতে একটি বই আছে সেগুলো সিরিজের পাতা এবং নীড় পেজের তাক থেকে লুকিয়ে রাখা হবে।",
|
||||||
"LabelSettingsHomePageBookshelfView": "নীড় পেজে বুকশেলফ ভিউ ব্যবহার করুন",
|
"LabelSettingsHomePageBookshelfView": "নীড় পেজে বুকশেলফ ভিউ ব্যবহার করুন",
|
||||||
"LabelSettingsLibraryBookshelfView": "লাইব্রেরি বুকশেলফ ভিউ ব্যবহার করুন",
|
"LabelSettingsLibraryBookshelfView": "লাইব্রেরি বুকশেলফ ভিউ ব্যবহার করুন",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "শতকরা সম্পূর্ণ এর চেয়ে বেশি",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "বাকি সময় (সেকেন্ড) এর চেয়ে কম",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "মিডিয়া আইটেমকে সমাপ্ত হিসাবে চিহ্নিত করুন যখন",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "কন্টিনিউ সিরিজে আগের বইগুলো এড়িয়ে যান",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "কন্টিনিউ সিরিজে আগের বইগুলো এড়িয়ে যান",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "কন্টিনিউ সিরিজের নীড় পেজ শেল্ফ দেখায় যে সিরিজে শুরু হয়নি এমন প্রথম বই যার অন্তত একটি বই শেষ হয়েছে এবং কোনো বই চলছে না। এই সেটিংটি সক্ষম করলে শুরু না হওয়া প্রথম বইটির পরিবর্তে সবচেয়ে দূরের সম্পূর্ণ বই থেকে সিরিজ চলতে থাকবে।",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "কন্টিনিউ সিরিজের নীড় পেজ শেল্ফ দেখায় যে সিরিজে শুরু হয়নি এমন প্রথম বই যার অন্তত একটি বই শেষ হয়েছে এবং কোনো বই চলছে না। এই সেটিংটি সক্ষম করলে শুরু না হওয়া প্রথম বইটির পরিবর্তে সবচেয়ে দূরের সম্পূর্ণ বই থেকে সিরিজ চলতে থাকবে।",
|
||||||
"LabelSettingsParseSubtitles": "সাবটাইটেল পার্স করুন",
|
"LabelSettingsParseSubtitles": "সাবটাইটেল পার্স করুন",
|
||||||
@@ -587,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} মিনিট",
|
"LabelTimeDurationXMinutes": "{0} মিনিট",
|
||||||
"LabelTimeDurationXSeconds": "{0} সেকেন্ড",
|
"LabelTimeDurationXSeconds": "{0} সেকেন্ড",
|
||||||
"LabelTimeInMinutes": "মিনিটে সময়",
|
"LabelTimeInMinutes": "মিনিটে সময়",
|
||||||
|
"LabelTimeLeft": "{0} বাকি",
|
||||||
"LabelTimeListened": "সময় শোনা হয়েছে",
|
"LabelTimeListened": "সময় শোনা হয়েছে",
|
||||||
"LabelTimeListenedToday": "আজ শোনার সময়",
|
"LabelTimeListenedToday": "আজ শোনার সময়",
|
||||||
"LabelTimeRemaining": "{0}টি অবশিষ্ট",
|
"LabelTimeRemaining": "{0}টি অবশিষ্ট",
|
||||||
@@ -594,6 +638,7 @@
|
|||||||
"LabelTitle": "শিরোনাম",
|
"LabelTitle": "শিরোনাম",
|
||||||
"LabelToolsEmbedMetadata": "মেটাডেটা এম্বেড করুন",
|
"LabelToolsEmbedMetadata": "মেটাডেটা এম্বেড করুন",
|
||||||
"LabelToolsEmbedMetadataDescription": "কভার ইমেজ এবং অধ্যায় সহ অডিও ফাইলগুলিতে মেটাডেটা এম্বেড করুন।",
|
"LabelToolsEmbedMetadataDescription": "কভার ইমেজ এবং অধ্যায় সহ অডিও ফাইলগুলিতে মেটাডেটা এম্বেড করুন।",
|
||||||
|
"LabelToolsM4bEncoder": "M4B এনকোডার",
|
||||||
"LabelToolsMakeM4b": "M4B অডিওবুক ফাইল তৈরি করুন",
|
"LabelToolsMakeM4b": "M4B অডিওবুক ফাইল তৈরি করুন",
|
||||||
"LabelToolsMakeM4bDescription": "এমবেডেড মেটাডেটা, কভার ইমেজ এবং অধ্যায় সহ একটি .M4B অডিওবুক ফাইল তৈরি করুন।",
|
"LabelToolsMakeM4bDescription": "এমবেডেড মেটাডেটা, কভার ইমেজ এবং অধ্যায় সহ একটি .M4B অডিওবুক ফাইল তৈরি করুন।",
|
||||||
"LabelToolsSplitM4b": "M4B কে MP3 তে বিভক্ত করুন",
|
"LabelToolsSplitM4b": "M4B কে MP3 তে বিভক্ত করুন",
|
||||||
@@ -606,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "মাল্টি-ট্র্যাক",
|
"LabelTracksMultiTrack": "মাল্টি-ট্র্যাক",
|
||||||
"LabelTracksNone": "কোন ট্র্যাক নেই",
|
"LabelTracksNone": "কোন ট্র্যাক নেই",
|
||||||
"LabelTracksSingleTrack": "একক-ট্র্যাক",
|
"LabelTracksSingleTrack": "একক-ট্র্যাক",
|
||||||
|
"LabelTrailer": "আনুগমিক",
|
||||||
"LabelType": "টাইপ",
|
"LabelType": "টাইপ",
|
||||||
"LabelUnabridged": "অসংলগ্ন",
|
"LabelUnabridged": "অসংলগ্ন",
|
||||||
"LabelUndo": "পূর্বাবস্থা",
|
"LabelUndo": "পূর্বাবস্থা",
|
||||||
@@ -617,10 +663,13 @@
|
|||||||
"LabelUpdateDetailsHelp": "একটি মিল থাকা অবস্থায় নির্বাচিত বইগুলির বিদ্যমান বিবরণ ওভাররাইট করার অনুমতি দিন",
|
"LabelUpdateDetailsHelp": "একটি মিল থাকা অবস্থায় নির্বাচিত বইগুলির বিদ্যমান বিবরণ ওভাররাইট করার অনুমতি দিন",
|
||||||
"LabelUpdatedAt": "আপডেট করা হয়েছে",
|
"LabelUpdatedAt": "আপডেট করা হয়েছে",
|
||||||
"LabelUploaderDragAndDrop": "ফাইল বা ফোল্ডার টেনে আনুন এবং ফেলে দিন",
|
"LabelUploaderDragAndDrop": "ফাইল বা ফোল্ডার টেনে আনুন এবং ফেলে দিন",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "ফাইল টেনে আনুন",
|
||||||
"LabelUploaderDropFiles": "ফাইলগুলো ফেলে দিন",
|
"LabelUploaderDropFiles": "ফাইলগুলো ফেলে দিন",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "স্বয়ংক্রিয়ভাবে শিরোনাম, লেখক এবং সিরিজ আনুন",
|
"LabelUploaderItemFetchMetadataHelp": "স্বয়ংক্রিয়ভাবে শিরোনাম, লেখক এবং সিরিজ আনুন",
|
||||||
|
"LabelUseAdvancedOptions": "উন্নত বিকল্প ব্যবহার করুন",
|
||||||
"LabelUseChapterTrack": "অধ্যায় ট্র্যাক ব্যবহার করুন",
|
"LabelUseChapterTrack": "অধ্যায় ট্র্যাক ব্যবহার করুন",
|
||||||
"LabelUseFullTrack": "সম্পূর্ণ ট্র্যাক ব্যবহার করুন",
|
"LabelUseFullTrack": "সম্পূর্ণ ট্র্যাক ব্যবহার করুন",
|
||||||
|
"LabelUseZeroForUnlimited": "অসীমের জন্য 0 ব্যবহার করুন",
|
||||||
"LabelUser": "ব্যবহারকারী",
|
"LabelUser": "ব্যবহারকারী",
|
||||||
"LabelUsername": "ব্যবহারকারীর নাম",
|
"LabelUsername": "ব্যবহারকারীর নাম",
|
||||||
"LabelValue": "মান",
|
"LabelValue": "মান",
|
||||||
@@ -667,6 +716,7 @@
|
|||||||
"MessageConfirmDeleteMetadataProvider": "আপনি কি নিশ্চিতভাবে কাস্টম মেটাডেটা প্রদানকারী \"{0}\" মুছতে চান?",
|
"MessageConfirmDeleteMetadataProvider": "আপনি কি নিশ্চিতভাবে কাস্টম মেটাডেটা প্রদানকারী \"{0}\" মুছতে চান?",
|
||||||
"MessageConfirmDeleteNotification": "আপনি কি নিশ্চিতভাবে এই বিজ্ঞপ্তিটি মুছতে চান?",
|
"MessageConfirmDeleteNotification": "আপনি কি নিশ্চিতভাবে এই বিজ্ঞপ্তিটি মুছতে চান?",
|
||||||
"MessageConfirmDeleteSession": "আপনি কি নিশ্চিত আপনি এই অধিবেশন মুছে দিতে চান?",
|
"MessageConfirmDeleteSession": "আপনি কি নিশ্চিত আপনি এই অধিবেশন মুছে দিতে চান?",
|
||||||
|
"MessageConfirmEmbedMetadataInAudioFiles": "আপনি কি {0}টি অডিও ফাইলে মেটাডেটা এম্বেড করার বিষয়ে নিশ্চিত?",
|
||||||
"MessageConfirmForceReScan": "আপনি কি নিশ্চিত যে আপনি জোর করে পুনরায় স্ক্যান করতে চান?",
|
"MessageConfirmForceReScan": "আপনি কি নিশ্চিত যে আপনি জোর করে পুনরায় স্ক্যান করতে চান?",
|
||||||
"MessageConfirmMarkAllEpisodesFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্ব সমাপ্ত হিসাবে চিহ্নিত করতে চান?",
|
"MessageConfirmMarkAllEpisodesFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্ব সমাপ্ত হিসাবে চিহ্নিত করতে চান?",
|
||||||
"MessageConfirmMarkAllEpisodesNotFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্বকে শেষ হয়নি বলে চিহ্নিত করতে চান?",
|
"MessageConfirmMarkAllEpisodesNotFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্বকে শেষ হয়নি বলে চিহ্নিত করতে চান?",
|
||||||
@@ -678,6 +728,7 @@
|
|||||||
"MessageConfirmPurgeCache": "ক্যাশে পরিষ্কারক <code>/metadata/cache</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে। <br /><br />আপনি কি নিশ্চিত আপনি ক্যাশে ডিরেক্টরি সরাতে চান?",
|
"MessageConfirmPurgeCache": "ক্যাশে পরিষ্কারক <code>/metadata/cache</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে। <br /><br />আপনি কি নিশ্চিত আপনি ক্যাশে ডিরেক্টরি সরাতে চান?",
|
||||||
"MessageConfirmPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কারক <code>/metadata/cache/items</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে।<br />আপনি কি নিশ্চিত?",
|
"MessageConfirmPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কারক <code>/metadata/cache/items</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে।<br />আপনি কি নিশ্চিত?",
|
||||||
"MessageConfirmQuickEmbed": "সতর্কতা! দ্রুত এম্বেড আপনার অডিও ফাইলের ব্যাকআপ করবে না। নিশ্চিত করুন যে আপনার অডিও ফাইলগুলির একটি ব্যাকআপ আছে। <br><br>আপনি কি চালিয়ে যেতে চান?",
|
"MessageConfirmQuickEmbed": "সতর্কতা! দ্রুত এম্বেড আপনার অডিও ফাইলের ব্যাকআপ করবে না। নিশ্চিত করুন যে আপনার অডিও ফাইলগুলির একটি ব্যাকআপ আছে। <br><br>আপনি কি চালিয়ে যেতে চান?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "একটি মিল পাওয়া গেলে দ্রুত ম্যাচিং পর্বগুলি বিস্তারিত ওভাররাইট করবে। শুধুমাত্র অতুলনীয় পর্ব আপডেট করা হবে। আপনি কি নিশ্চিত?",
|
||||||
"MessageConfirmReScanLibraryItems": "আপনি কি নিশ্চিত যে আপনি {0}টি আইটেম পুনরায় স্ক্যান করতে চান?",
|
"MessageConfirmReScanLibraryItems": "আপনি কি নিশ্চিত যে আপনি {0}টি আইটেম পুনরায় স্ক্যান করতে চান?",
|
||||||
"MessageConfirmRemoveAllChapters": "আপনি কি নিশ্চিত যে আপনি সমস্ত অধ্যায় সরাতে চান?",
|
"MessageConfirmRemoveAllChapters": "আপনি কি নিশ্চিত যে আপনি সমস্ত অধ্যায় সরাতে চান?",
|
||||||
"MessageConfirmRemoveAuthor": "আপনি কি নিশ্চিত যে আপনি লেখক \"{0}\" অপসারণ করতে চান?",
|
"MessageConfirmRemoveAuthor": "আপনি কি নিশ্চিত যে আপনি লেখক \"{0}\" অপসারণ করতে চান?",
|
||||||
@@ -685,6 +736,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "আপনি কি নিশ্চিত আপনি \"{0}\" পর্বটি সরাতে চান?",
|
"MessageConfirmRemoveEpisode": "আপনি কি নিশ্চিত আপনি \"{0}\" পর্বটি সরাতে চান?",
|
||||||
"MessageConfirmRemoveEpisodes": "আপনি কি নিশ্চিত যে আপনি {0}টি পর্ব সরাতে চান?",
|
"MessageConfirmRemoveEpisodes": "আপনি কি নিশ্চিত যে আপনি {0}টি পর্ব সরাতে চান?",
|
||||||
"MessageConfirmRemoveListeningSessions": "আপনি কি নিশ্চিত যে আপনি {0}টি শোনার সেশন সরাতে চান?",
|
"MessageConfirmRemoveListeningSessions": "আপনি কি নিশ্চিত যে আপনি {0}টি শোনার সেশন সরাতে চান?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "আপনি কি আপনার লাইব্রেরি আইটেম ফোল্ডারে থাকা সমস্ত মেটাডেটা {0} ফাইল মুছে ফেলার বিষয়ে নিশ্চিত?",
|
||||||
"MessageConfirmRemoveNarrator": "আপনি কি \"{0}\" বর্ণনাকারীকে সরানোর বিষয়ে নিশ্চিত?",
|
"MessageConfirmRemoveNarrator": "আপনি কি \"{0}\" বর্ণনাকারীকে সরানোর বিষয়ে নিশ্চিত?",
|
||||||
"MessageConfirmRemovePlaylist": "আপনি কি নিশ্চিত যে আপনি আপনার প্লেলিস্ট \"{0}\" সরাতে চান?",
|
"MessageConfirmRemovePlaylist": "আপনি কি নিশ্চিত যে আপনি আপনার প্লেলিস্ট \"{0}\" সরাতে চান?",
|
||||||
"MessageConfirmRenameGenre": "আপনি কি নিশ্চিত যে আপনি সমস্ত আইটেমের জন্য \"{0}\" ধারার নাম পরিবর্তন করে \"{1}\" করতে চান?",
|
"MessageConfirmRenameGenre": "আপনি কি নিশ্চিত যে আপনি সমস্ত আইটেমের জন্য \"{0}\" ধারার নাম পরিবর্তন করে \"{1}\" করতে চান?",
|
||||||
@@ -700,6 +752,7 @@
|
|||||||
"MessageDragFilesIntoTrackOrder": "সঠিক ট্র্যাক অর্ডারে ফাইল টেনে আনুন",
|
"MessageDragFilesIntoTrackOrder": "সঠিক ট্র্যাক অর্ডারে ফাইল টেনে আনুন",
|
||||||
"MessageEmbedFailed": "এম্বেড ব্যর্থ হয়েছে!",
|
"MessageEmbedFailed": "এম্বেড ব্যর্থ হয়েছে!",
|
||||||
"MessageEmbedFinished": "এম্বেড করা শেষ!",
|
"MessageEmbedFinished": "এম্বেড করা শেষ!",
|
||||||
|
"MessageEmbedQueue": "মেটাডেটা এম্বেডের জন্য সারিবদ্ধ ({0} সারিতে)",
|
||||||
"MessageEpisodesQueuedForDownload": "{0} পর্ব(গুলি) ডাউনলোডের জন্য সারিবদ্ধ",
|
"MessageEpisodesQueuedForDownload": "{0} পর্ব(গুলি) ডাউনলোডের জন্য সারিবদ্ধ",
|
||||||
"MessageEreaderDevices": "ই-বুক সরবরাহ নিশ্চিত করতে, আপনাকে নীচে তালিকাভুক্ত প্রতিটি ডিভাইসের জন্য একটি বৈধ প্রেরক হিসাবে উপরের ইমেল ঠিকানাটি যুক্ত করতে হতে পারে।",
|
"MessageEreaderDevices": "ই-বুক সরবরাহ নিশ্চিত করতে, আপনাকে নীচে তালিকাভুক্ত প্রতিটি ডিভাইসের জন্য একটি বৈধ প্রেরক হিসাবে উপরের ইমেল ঠিকানাটি যুক্ত করতে হতে পারে।",
|
||||||
"MessageFeedURLWillBe": "ফিড URL হবে {0}",
|
"MessageFeedURLWillBe": "ফিড URL হবে {0}",
|
||||||
@@ -744,6 +797,7 @@
|
|||||||
"MessageNoLogs": "কোনও লগ নেই",
|
"MessageNoLogs": "কোনও লগ নেই",
|
||||||
"MessageNoMediaProgress": "মিডিয়া অগ্রগতি নেই",
|
"MessageNoMediaProgress": "মিডিয়া অগ্রগতি নেই",
|
||||||
"MessageNoNotifications": "কোনো বিজ্ঞপ্তি নেই",
|
"MessageNoNotifications": "কোনো বিজ্ঞপ্তি নেই",
|
||||||
|
"MessageNoPodcastFeed": "অবৈধ পডকাস্ট: কোনো ফিড নেই",
|
||||||
"MessageNoPodcastsFound": "কোন পডকাস্ট পাওয়া যায়নি",
|
"MessageNoPodcastsFound": "কোন পডকাস্ট পাওয়া যায়নি",
|
||||||
"MessageNoResults": "কোন ফলাফল নেই",
|
"MessageNoResults": "কোন ফলাফল নেই",
|
||||||
"MessageNoSearchResultsFor": "\"{0}\" এর জন্য কোন অনুসন্ধান ফলাফল নেই",
|
"MessageNoSearchResultsFor": "\"{0}\" এর জন্য কোন অনুসন্ধান ফলাফল নেই",
|
||||||
@@ -760,6 +814,10 @@
|
|||||||
"MessagePlaylistCreateFromCollection": "সংগ্রহ থেকে প্লেলিস্ট তৈরি করুন",
|
"MessagePlaylistCreateFromCollection": "সংগ্রহ থেকে প্লেলিস্ট তৈরি করুন",
|
||||||
"MessagePleaseWait": "অনুগ্রহ করে অপেক্ষা করুন..।",
|
"MessagePleaseWait": "অনুগ্রহ করে অপেক্ষা করুন..।",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "পডকাস্টের সাথে মিলের জন্য ব্যবহার করার জন্য কোন RSS ফিড ইউআরএল নেই",
|
"MessagePodcastHasNoRSSFeedForMatching": "পডকাস্টের সাথে মিলের জন্য ব্যবহার করার জন্য কোন RSS ফিড ইউআরএল নেই",
|
||||||
|
"MessagePodcastSearchField": "অনুসন্ধান শব্দ বা RSS ফিড URL লিখুন",
|
||||||
|
"MessageQuickEmbedInProgress": "দ্রুত এম্বেড করা হচ্ছে",
|
||||||
|
"MessageQuickEmbedQueue": "দ্রুত এম্বেড করার জন্য সারিবদ্ধ ({0} সারিতে)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "দ্রুত ম্যাচ সব পর্ব",
|
||||||
"MessageQuickMatchDescription": "খালি আইটেমের বিশদ বিবরণ এবং '{0}' থেকে প্রথম ম্যাচের ফলাফলের সাথে কভার করুন। সার্ভার সেটিং সক্ষম না থাকলে বিশদ ওভাররাইট করে না।",
|
"MessageQuickMatchDescription": "খালি আইটেমের বিশদ বিবরণ এবং '{0}' থেকে প্রথম ম্যাচের ফলাফলের সাথে কভার করুন। সার্ভার সেটিং সক্ষম না থাকলে বিশদ ওভাররাইট করে না।",
|
||||||
"MessageRemoveChapter": "অধ্যায় সরান",
|
"MessageRemoveChapter": "অধ্যায় সরান",
|
||||||
"MessageRemoveEpisodes": "{0}টি পর্ব(গুলি) সরান",
|
"MessageRemoveEpisodes": "{0}টি পর্ব(গুলি) সরান",
|
||||||
@@ -802,6 +860,9 @@
|
|||||||
"MessageTaskOpmlImportFeedPodcastExists": "পডকাস্ট আগে থেকেই পাথে বিদ্যমান",
|
"MessageTaskOpmlImportFeedPodcastExists": "পডকাস্ট আগে থেকেই পাথে বিদ্যমান",
|
||||||
"MessageTaskOpmlImportFeedPodcastFailed": "পডকাস্ট তৈরি করতে ব্যর্থ",
|
"MessageTaskOpmlImportFeedPodcastFailed": "পডকাস্ট তৈরি করতে ব্যর্থ",
|
||||||
"MessageTaskOpmlImportFinished": "{0}টি পডকাস্ট যোগ করা হয়েছে",
|
"MessageTaskOpmlImportFinished": "{0}টি পডকাস্ট যোগ করা হয়েছে",
|
||||||
|
"MessageTaskOpmlParseFailed": "OPML ফাইল পার্স করতে ব্যর্থ হয়েছে",
|
||||||
|
"MessageTaskOpmlParseFastFail": "অবৈধ OPML ফাইল <opml> ট্যাগ পাওয়া যায়নি বা একটি <outline> ট্যাগ পাওয়া যায়নি",
|
||||||
|
"MessageTaskOpmlParseNoneFound": "OPML ফাইলে কোনো ফিড পাওয়া যায়নি",
|
||||||
"MessageTaskScanItemsAdded": "{0}টি করা হয়েছে",
|
"MessageTaskScanItemsAdded": "{0}টি করা হয়েছে",
|
||||||
"MessageTaskScanItemsMissing": "{0}টি অনুপস্থিত",
|
"MessageTaskScanItemsMissing": "{0}টি অনুপস্থিত",
|
||||||
"MessageTaskScanItemsUpdated": "{0} টি আপডেট করা হয়েছে",
|
"MessageTaskScanItemsUpdated": "{0} টি আপডেট করা হয়েছে",
|
||||||
@@ -826,6 +887,10 @@
|
|||||||
"NoteUploaderFoldersWithMediaFiles": "মিডিয়া ফাইল সহ ফোল্ডারগুলি আলাদা লাইব্রেরি আইটেম হিসাবে পরিচালনা করা হবে।",
|
"NoteUploaderFoldersWithMediaFiles": "মিডিয়া ফাইল সহ ফোল্ডারগুলি আলাদা লাইব্রেরি আইটেম হিসাবে পরিচালনা করা হবে।",
|
||||||
"NoteUploaderOnlyAudioFiles": "যদি শুধুমাত্র অডিও ফাইল আপলোড করা হয় তবে প্রতিটি অডিও ফাইল একটি পৃথক অডিওবুক হিসাবে পরিচালনা করা হবে।",
|
"NoteUploaderOnlyAudioFiles": "যদি শুধুমাত্র অডিও ফাইল আপলোড করা হয় তবে প্রতিটি অডিও ফাইল একটি পৃথক অডিওবুক হিসাবে পরিচালনা করা হবে।",
|
||||||
"NoteUploaderUnsupportedFiles": "অসমর্থিত ফাইলগুলি উপেক্ষা করা হয়। একটি ফোল্ডার বেছে নেওয়া বা ফেলে দেওয়ার সময়, আইটেম ফোল্ডারে নেই এমন অন্যান্য ফাইলগুলি উপেক্ষা করা হয়।",
|
"NoteUploaderUnsupportedFiles": "অসমর্থিত ফাইলগুলি উপেক্ষা করা হয়। একটি ফোল্ডার বেছে নেওয়া বা ফেলে দেওয়ার সময়, আইটেম ফোল্ডারে নেই এমন অন্যান্য ফাইলগুলি উপেক্ষা করা হয়।",
|
||||||
|
"NotificationOnBackupCompletedDescription": "ব্যাকআপ সম্পূর্ণ হলে ট্রিগার হবে",
|
||||||
|
"NotificationOnBackupFailedDescription": "ব্যাকআপ ব্যর্থ হলে ট্রিগার হবে",
|
||||||
|
"NotificationOnEpisodeDownloadedDescription": "একটি পডকাস্ট পর্ব স্বয়ংক্রিয়ভাবে ডাউনলোড হলে ট্রিগার হবে",
|
||||||
|
"NotificationOnTestDescription": "বিজ্ঞপ্তি সিস্টেম পরীক্ষার জন্য ইভেন্ট",
|
||||||
"PlaceholderNewCollection": "নতুন সংগ্রহের নাম",
|
"PlaceholderNewCollection": "নতুন সংগ্রহের নাম",
|
||||||
"PlaceholderNewFolderPath": "নতুন ফোল্ডার পথ",
|
"PlaceholderNewFolderPath": "নতুন ফোল্ডার পথ",
|
||||||
"PlaceholderNewPlaylist": "নতুন প্লেলিস্টের নাম",
|
"PlaceholderNewPlaylist": "নতুন প্লেলিস্টের নাম",
|
||||||
@@ -851,6 +916,7 @@
|
|||||||
"StatsYearInReview": "বাৎসরিক পর্যালোচনা",
|
"StatsYearInReview": "বাৎসরিক পর্যালোচনা",
|
||||||
"ToastAccountUpdateSuccess": "অ্যাকাউন্ট আপডেট করা হয়েছে",
|
"ToastAccountUpdateSuccess": "অ্যাকাউন্ট আপডেট করা হয়েছে",
|
||||||
"ToastAppriseUrlRequired": "একটি Apprise ইউআরএল লিখতে হবে",
|
"ToastAppriseUrlRequired": "একটি Apprise ইউআরএল লিখতে হবে",
|
||||||
|
"ToastAsinRequired": "ASIN প্রয়োজন",
|
||||||
"ToastAuthorImageRemoveSuccess": "লেখকের ছবি সরানো হয়েছে",
|
"ToastAuthorImageRemoveSuccess": "লেখকের ছবি সরানো হয়েছে",
|
||||||
"ToastAuthorNotFound": "লেখক \"{0}\" খুঁজে পাওয়া যায়নি",
|
"ToastAuthorNotFound": "লেখক \"{0}\" খুঁজে পাওয়া যায়নি",
|
||||||
"ToastAuthorRemoveSuccess": "লেখক সরানো হয়েছে",
|
"ToastAuthorRemoveSuccess": "লেখক সরানো হয়েছে",
|
||||||
@@ -870,6 +936,8 @@
|
|||||||
"ToastBackupUploadSuccess": "ব্যাকআপ আপলোড হয়েছে",
|
"ToastBackupUploadSuccess": "ব্যাকআপ আপলোড হয়েছে",
|
||||||
"ToastBatchDeleteFailed": "ব্যাচ মুছে ফেলতে ব্যর্থ হয়েছে",
|
"ToastBatchDeleteFailed": "ব্যাচ মুছে ফেলতে ব্যর্থ হয়েছে",
|
||||||
"ToastBatchDeleteSuccess": "ব্যাচ মুছে ফেলা সফল হয়েছে",
|
"ToastBatchDeleteSuccess": "ব্যাচ মুছে ফেলা সফল হয়েছে",
|
||||||
|
"ToastBatchQuickMatchFailed": "ব্যাচ কুইক ম্যাচ ব্যর্থ!",
|
||||||
|
"ToastBatchQuickMatchStarted": "{0}টি বইয়ের ব্যাচ কুইক ম্যাচ শুরু হয়েছে!",
|
||||||
"ToastBatchUpdateFailed": "ব্যাচ আপডেট ব্যর্থ হয়েছে",
|
"ToastBatchUpdateFailed": "ব্যাচ আপডেট ব্যর্থ হয়েছে",
|
||||||
"ToastBatchUpdateSuccess": "ব্যাচ আপডেট সাফল্য",
|
"ToastBatchUpdateSuccess": "ব্যাচ আপডেট সাফল্য",
|
||||||
"ToastBookmarkCreateFailed": "বুকমার্ক তৈরি করতে ব্যর্থ",
|
"ToastBookmarkCreateFailed": "বুকমার্ক তৈরি করতে ব্যর্থ",
|
||||||
@@ -881,6 +949,7 @@
|
|||||||
"ToastChaptersHaveErrors": "অধ্যায়ে ত্রুটি আছে",
|
"ToastChaptersHaveErrors": "অধ্যায়ে ত্রুটি আছে",
|
||||||
"ToastChaptersMustHaveTitles": "অধ্যায়ের শিরোনাম থাকতে হবে",
|
"ToastChaptersMustHaveTitles": "অধ্যায়ের শিরোনাম থাকতে হবে",
|
||||||
"ToastChaptersRemoved": "অধ্যায়গুলো মুছে ফেলা হয়েছে",
|
"ToastChaptersRemoved": "অধ্যায়গুলো মুছে ফেলা হয়েছে",
|
||||||
|
"ToastChaptersUpdated": "অধ্যায় আপডেট করা হয়েছে",
|
||||||
"ToastCollectionItemsAddFailed": "আইটেম(গুলি) সংগ্রহে যোগ করা ব্যর্থ হয়েছে",
|
"ToastCollectionItemsAddFailed": "আইটেম(গুলি) সংগ্রহে যোগ করা ব্যর্থ হয়েছে",
|
||||||
"ToastCollectionItemsAddSuccess": "আইটেম(গুলি) সংগ্রহে যোগ করা সফল হয়েছে",
|
"ToastCollectionItemsAddSuccess": "আইটেম(গুলি) সংগ্রহে যোগ করা সফল হয়েছে",
|
||||||
"ToastCollectionItemsRemoveSuccess": "আইটেম(গুলি) সংগ্রহ থেকে সরানো হয়েছে",
|
"ToastCollectionItemsRemoveSuccess": "আইটেম(গুলি) সংগ্রহ থেকে সরানো হয়েছে",
|
||||||
@@ -898,11 +967,14 @@
|
|||||||
"ToastEncodeCancelSucces": "এনকোড বাতিল করা হয়েছে",
|
"ToastEncodeCancelSucces": "এনকোড বাতিল করা হয়েছে",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "সারি সাফ করতে ব্যর্থ হয়েছে",
|
"ToastEpisodeDownloadQueueClearFailed": "সারি সাফ করতে ব্যর্থ হয়েছে",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "পর্ব ডাউনলোড সারি পরিষ্কার করা হয়েছে",
|
"ToastEpisodeDownloadQueueClearSuccess": "পর্ব ডাউনলোড সারি পরিষ্কার করা হয়েছে",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0}টি পর্ব আপডেট করা হয়েছে",
|
||||||
"ToastErrorCannotShare": "এই ডিভাইসে স্থানীয়ভাবে শেয়ার করা যাবে না",
|
"ToastErrorCannotShare": "এই ডিভাইসে স্থানীয়ভাবে শেয়ার করা যাবে না",
|
||||||
"ToastFailedToLoadData": "ডেটা লোড করা যায়নি",
|
"ToastFailedToLoadData": "ডেটা লোড করা যায়নি",
|
||||||
|
"ToastFailedToMatch": "মেলাতে ব্যর্থ হয়েছে",
|
||||||
"ToastFailedToShare": "শেয়ার করতে ব্যর্থ",
|
"ToastFailedToShare": "শেয়ার করতে ব্যর্থ",
|
||||||
"ToastFailedToUpdate": "আপডেট করতে ব্যর্থ হয়েছে",
|
"ToastFailedToUpdate": "আপডেট করতে ব্যর্থ হয়েছে",
|
||||||
"ToastInvalidImageUrl": "অকার্যকর ছবির ইউআরএল",
|
"ToastInvalidImageUrl": "অকার্যকর ছবির ইউআরএল",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "ডাউনলোড করার জন্য অবৈধ সর্বোচ্চ পর্ব",
|
||||||
"ToastInvalidUrl": "অকার্যকর ইউআরএল",
|
"ToastInvalidUrl": "অকার্যকর ইউআরএল",
|
||||||
"ToastItemCoverUpdateSuccess": "আইটেম কভার আপডেট করা হয়েছে",
|
"ToastItemCoverUpdateSuccess": "আইটেম কভার আপডেট করা হয়েছে",
|
||||||
"ToastItemDeletedFailed": "আইটেম মুছে ফেলতে ব্যর্থ",
|
"ToastItemDeletedFailed": "আইটেম মুছে ফেলতে ব্যর্থ",
|
||||||
@@ -920,14 +992,22 @@
|
|||||||
"ToastLibraryScanFailedToStart": "স্ক্যান শুরু করতে ব্যর্থ",
|
"ToastLibraryScanFailedToStart": "স্ক্যান শুরু করতে ব্যর্থ",
|
||||||
"ToastLibraryScanStarted": "লাইব্রেরি স্ক্যান শুরু হয়েছে",
|
"ToastLibraryScanStarted": "লাইব্রেরি স্ক্যান শুরু হয়েছে",
|
||||||
"ToastLibraryUpdateSuccess": "লাইব্রেরি \"{0}\" আপডেট করা হয়েছে",
|
"ToastLibraryUpdateSuccess": "লাইব্রেরি \"{0}\" আপডেট করা হয়েছে",
|
||||||
|
"ToastMatchAllAuthorsFailed": "সমস্ত লেখকের সাথে মিলতে ব্যর্থ হয়েছে",
|
||||||
|
"ToastMetadataFilesRemovedError": "মেটাডেটা সরানোর সময় ত্রুটি {0} ফাইল",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "কোনো মেটাডেটা নেই।লাইব্রেরিতে {0} ফাইল পাওয়া গেছে",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "কোনো মেটাডেটা নেই।{0} ফাইল সরানো হয়েছে",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} মেটাডেটা৷{1} ফাইল সরানো হয়েছে",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "অন্তত একটি পথ থাকতে হবে",
|
||||||
"ToastNameEmailRequired": "নাম এবং ইমেইল আবশ্যক",
|
"ToastNameEmailRequired": "নাম এবং ইমেইল আবশ্যক",
|
||||||
"ToastNameRequired": "নাম আবশ্যক",
|
"ToastNameRequired": "নাম আবশ্যক",
|
||||||
|
"ToastNewEpisodesFound": "{0}টি নতুন পর্ব পাওয়া গেছে",
|
||||||
"ToastNewUserCreatedFailed": "অ্যাকাউন্ট তৈরি করতে ব্যর্থ: \"{0}\"",
|
"ToastNewUserCreatedFailed": "অ্যাকাউন্ট তৈরি করতে ব্যর্থ: \"{0}\"",
|
||||||
"ToastNewUserCreatedSuccess": "নতুন একাউন্ট তৈরি হয়েছে",
|
"ToastNewUserCreatedSuccess": "নতুন একাউন্ট তৈরি হয়েছে",
|
||||||
"ToastNewUserLibraryError": "অন্তত একটি লাইব্রেরি নির্বাচন করতে হবে",
|
"ToastNewUserLibraryError": "অন্তত একটি লাইব্রেরি নির্বাচন করতে হবে",
|
||||||
"ToastNewUserPasswordError": "অন্তত একটি পাসওয়ার্ড থাকতে হবে, শুধুমাত্র রুট ব্যবহারকারীর একটি খালি পাসওয়ার্ড থাকতে পারে",
|
"ToastNewUserPasswordError": "অন্তত একটি পাসওয়ার্ড থাকতে হবে, শুধুমাত্র রুট ব্যবহারকারীর একটি খালি পাসওয়ার্ড থাকতে পারে",
|
||||||
"ToastNewUserTagError": "অন্তত একটি ট্যাগ নির্বাচন করতে হবে",
|
"ToastNewUserTagError": "অন্তত একটি ট্যাগ নির্বাচন করতে হবে",
|
||||||
"ToastNewUserUsernameError": "একটি ব্যবহারকারীর নাম লিখুন",
|
"ToastNewUserUsernameError": "একটি ব্যবহারকারীর নাম লিখুন",
|
||||||
|
"ToastNoNewEpisodesFound": "কোন নতুন পর্ব পাওয়া যায়নি",
|
||||||
"ToastNoUpdatesNecessary": "কোন আপডেটের প্রয়োজন নেই",
|
"ToastNoUpdatesNecessary": "কোন আপডেটের প্রয়োজন নেই",
|
||||||
"ToastNotificationCreateFailed": "বিজ্ঞপ্তি তৈরি করতে ব্যর্থ",
|
"ToastNotificationCreateFailed": "বিজ্ঞপ্তি তৈরি করতে ব্যর্থ",
|
||||||
"ToastNotificationDeleteFailed": "বিজ্ঞপ্তি মুছে ফেলতে ব্যর্থ",
|
"ToastNotificationDeleteFailed": "বিজ্ঞপ্তি মুছে ফেলতে ব্যর্থ",
|
||||||
@@ -946,6 +1026,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "পডকাস্ট ফিড পেতে ব্যর্থ হয়েছে",
|
"ToastPodcastGetFeedFailed": "পডকাস্ট ফিড পেতে ব্যর্থ হয়েছে",
|
||||||
"ToastPodcastNoEpisodesInFeed": "আরএসএস ফিডে কোনো পর্ব পাওয়া যায়নি",
|
"ToastPodcastNoEpisodesInFeed": "আরএসএস ফিডে কোনো পর্ব পাওয়া যায়নি",
|
||||||
"ToastPodcastNoRssFeed": "পডকাস্টের কোন আরএসএস ফিড নেই",
|
"ToastPodcastNoRssFeed": "পডকাস্টের কোন আরএসএস ফিড নেই",
|
||||||
|
"ToastProgressIsNotBeingSynced": "অগ্রগতি সিঙ্ক হচ্ছে না, প্লেব্যাক পুনরায় চালু করুন",
|
||||||
"ToastProviderCreatedFailed": "প্রদানকারী যোগ করতে ব্যর্থ হয়েছে",
|
"ToastProviderCreatedFailed": "প্রদানকারী যোগ করতে ব্যর্থ হয়েছে",
|
||||||
"ToastProviderCreatedSuccess": "নতুন প্রদানকারী যোগ করা হয়েছে",
|
"ToastProviderCreatedSuccess": "নতুন প্রদানকারী যোগ করা হয়েছে",
|
||||||
"ToastProviderNameAndUrlRequired": "নাম এবং ইউআরএল আবশ্যক",
|
"ToastProviderNameAndUrlRequired": "নাম এবং ইউআরএল আবশ্যক",
|
||||||
@@ -972,6 +1053,7 @@
|
|||||||
"ToastSessionCloseFailed": "অধিবেশন বন্ধ করতে ব্যর্থ হয়েছে",
|
"ToastSessionCloseFailed": "অধিবেশন বন্ধ করতে ব্যর্থ হয়েছে",
|
||||||
"ToastSessionDeleteFailed": "সেশন মুছে ফেলতে ব্যর্থ",
|
"ToastSessionDeleteFailed": "সেশন মুছে ফেলতে ব্যর্থ",
|
||||||
"ToastSessionDeleteSuccess": "সেশন মুছে ফেলা হয়েছে",
|
"ToastSessionDeleteSuccess": "সেশন মুছে ফেলা হয়েছে",
|
||||||
|
"ToastSleepTimerDone": "স্লিপ টাইমার হয়ে গেছে... zZzzZz",
|
||||||
"ToastSlugMustChange": "স্লাগে অবৈধ অক্ষর রয়েছে",
|
"ToastSlugMustChange": "স্লাগে অবৈধ অক্ষর রয়েছে",
|
||||||
"ToastSlugRequired": "স্লাগ আবশ্যক",
|
"ToastSlugRequired": "স্লাগ আবশ্যক",
|
||||||
"ToastSocketConnected": "সকেট সংযুক্ত",
|
"ToastSocketConnected": "সকেট সংযুক্ত",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+15
-1
@@ -19,6 +19,7 @@
|
|||||||
"ButtonChooseFiles": "Vybrat soubory",
|
"ButtonChooseFiles": "Vybrat soubory",
|
||||||
"ButtonClearFilter": "Vymazat filtr",
|
"ButtonClearFilter": "Vymazat filtr",
|
||||||
"ButtonCloseFeed": "Zavřít kanál",
|
"ButtonCloseFeed": "Zavřít kanál",
|
||||||
|
"ButtonCloseSession": "Zavřít otevřenou relaci",
|
||||||
"ButtonCollections": "Kolekce",
|
"ButtonCollections": "Kolekce",
|
||||||
"ButtonConfigureScanner": "Konfigurovat Prohledávání",
|
"ButtonConfigureScanner": "Konfigurovat Prohledávání",
|
||||||
"ButtonCreate": "Vytvořit",
|
"ButtonCreate": "Vytvořit",
|
||||||
@@ -29,6 +30,8 @@
|
|||||||
"ButtonEditChapters": "Upravit kapitoly",
|
"ButtonEditChapters": "Upravit kapitoly",
|
||||||
"ButtonEditPodcast": "Upravit podcast",
|
"ButtonEditPodcast": "Upravit podcast",
|
||||||
"ButtonEnable": "Povolit",
|
"ButtonEnable": "Povolit",
|
||||||
|
"ButtonFireAndFail": "Spustit a selhat",
|
||||||
|
"ButtonFireOnTest": "Spustit událost onTest",
|
||||||
"ButtonForceReScan": "Vynutit opětovné prohledání",
|
"ButtonForceReScan": "Vynutit opětovné prohledání",
|
||||||
"ButtonFullPath": "Úplná cesta",
|
"ButtonFullPath": "Úplná cesta",
|
||||||
"ButtonHide": "Skrýt",
|
"ButtonHide": "Skrýt",
|
||||||
@@ -58,11 +61,13 @@
|
|||||||
"ButtonPlaylists": "Seznamy skladeb",
|
"ButtonPlaylists": "Seznamy skladeb",
|
||||||
"ButtonPrevious": "Předchozí",
|
"ButtonPrevious": "Předchozí",
|
||||||
"ButtonPreviousChapter": "Předchozí Kapitola",
|
"ButtonPreviousChapter": "Předchozí Kapitola",
|
||||||
|
"ButtonProbeAudioFile": "Prozkoumat audio soubor",
|
||||||
"ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť",
|
"ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť",
|
||||||
"ButtonPurgeItemsCache": "Vyčistit mezipaměť položek",
|
"ButtonPurgeItemsCache": "Vyčistit mezipaměť položek",
|
||||||
"ButtonQueueAddItem": "Přidat do fronty",
|
"ButtonQueueAddItem": "Přidat do fronty",
|
||||||
"ButtonQueueRemoveItem": "Odstranit z fronty",
|
"ButtonQueueRemoveItem": "Odstranit z fronty",
|
||||||
"ButtonQuickEmbedMetadata": "Rychle Zapsat Metadata",
|
"ButtonQuickEmbed": "Rychle Zapsat",
|
||||||
|
"ButtonQuickEmbedMetadata": "Rychle zapsat Metadata",
|
||||||
"ButtonQuickMatch": "Rychlé přiřazení",
|
"ButtonQuickMatch": "Rychlé přiřazení",
|
||||||
"ButtonReScan": "Znovu prohledat",
|
"ButtonReScan": "Znovu prohledat",
|
||||||
"ButtonRead": "Číst",
|
"ButtonRead": "Číst",
|
||||||
@@ -158,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Aktualizovat notifikaci",
|
"HeaderNotificationUpdate": "Aktualizovat notifikaci",
|
||||||
"HeaderNotifications": "Oznámení",
|
"HeaderNotifications": "Oznámení",
|
||||||
"HeaderOpenIDConnectAuthentication": "Ověřování pomocí OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Ověřování pomocí OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Otevřené relace přehrávače",
|
||||||
"HeaderOpenRSSFeed": "Otevřít RSS kanál",
|
"HeaderOpenRSSFeed": "Otevřít RSS kanál",
|
||||||
"HeaderOtherFiles": "Ostatní soubory",
|
"HeaderOtherFiles": "Ostatní soubory",
|
||||||
"HeaderPasswordAuthentication": "Autentizace heslem",
|
"HeaderPasswordAuthentication": "Autentizace heslem",
|
||||||
@@ -175,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Odstranit {0} epizody",
|
"HeaderRemoveEpisodes": "Odstranit {0} epizody",
|
||||||
"HeaderSavedMediaProgress": "Průběh uložených médií",
|
"HeaderSavedMediaProgress": "Průběh uložených médií",
|
||||||
"HeaderSchedule": "Plán",
|
"HeaderSchedule": "Plán",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Naplánovat automatické stahování epizod",
|
||||||
"HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven",
|
"HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven",
|
||||||
"HeaderSession": "Relace",
|
"HeaderSession": "Relace",
|
||||||
"HeaderSetBackupSchedule": "Nastavit plán zálohování",
|
"HeaderSetBackupSchedule": "Nastavit plán zálohování",
|
||||||
@@ -220,7 +227,11 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
|
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
|
||||||
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
|
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
|
||||||
"LabelAlreadyInYourLibrary": "Již ve vaší knihovně",
|
"LabelAlreadyInYourLibrary": "Již ve vaší knihovně",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Připojit",
|
"LabelAppend": "Připojit",
|
||||||
|
"LabelAudioBitrate": "Bitový tok zvuku (např. 128k)",
|
||||||
|
"LabelAudioChannels": "Zvukové kanály (1 nebo 2)",
|
||||||
|
"LabelAudioCodec": "Kodek audia",
|
||||||
"LabelAuthor": "Autor",
|
"LabelAuthor": "Autor",
|
||||||
"LabelAuthorFirstLast": "Autor (jméno a příjmení)",
|
"LabelAuthorFirstLast": "Autor (jméno a příjmení)",
|
||||||
"LabelAuthorLastFirst": "Autor (příjmení a jméno)",
|
"LabelAuthorLastFirst": "Autor (příjmení a jméno)",
|
||||||
@@ -233,6 +244,7 @@
|
|||||||
"LabelAutoRegister": "Automatická registrace",
|
"LabelAutoRegister": "Automatická registrace",
|
||||||
"LabelAutoRegisterDescription": "Automaticky vytvářet nové uživatele po přihlášení",
|
"LabelAutoRegisterDescription": "Automaticky vytvářet nové uživatele po přihlášení",
|
||||||
"LabelBackToUser": "Zpět k uživateli",
|
"LabelBackToUser": "Zpět k uživateli",
|
||||||
|
"LabelBackupAudioFiles": "Zálohovat zvukové soubory",
|
||||||
"LabelBackupLocation": "Umístění zálohy",
|
"LabelBackupLocation": "Umístění zálohy",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
|
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
|
||||||
@@ -241,11 +253,13 @@
|
|||||||
"LabelBackupsNumberToKeep": "Počet záloh, které se mají uchovat",
|
"LabelBackupsNumberToKeep": "Počet záloh, které se mají uchovat",
|
||||||
"LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.",
|
"LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.",
|
||||||
"LabelBitrate": "Datový tok",
|
"LabelBitrate": "Datový tok",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Knihy",
|
"LabelBooks": "Knihy",
|
||||||
"LabelButtonText": "Text tlačítka",
|
"LabelButtonText": "Text tlačítka",
|
||||||
"LabelByAuthor": "od {0}",
|
"LabelByAuthor": "od {0}",
|
||||||
"LabelChangePassword": "Změnit heslo",
|
"LabelChangePassword": "Změnit heslo",
|
||||||
"LabelChannels": "Kanály",
|
"LabelChannels": "Kanály",
|
||||||
|
"LabelChapterCount": "{0} Kapitol",
|
||||||
"LabelChapterTitle": "Název kapitoly",
|
"LabelChapterTitle": "Název kapitoly",
|
||||||
"LabelChapters": "Kapitoly",
|
"LabelChapters": "Kapitoly",
|
||||||
"LabelChaptersFound": "Kapitoly nalezeny",
|
"LabelChaptersFound": "Kapitoly nalezeny",
|
||||||
|
|||||||
+71
-8
@@ -71,8 +71,8 @@
|
|||||||
"ButtonQuickMatch": "Schnellabgleich",
|
"ButtonQuickMatch": "Schnellabgleich",
|
||||||
"ButtonReScan": "Neu scannen",
|
"ButtonReScan": "Neu scannen",
|
||||||
"ButtonRead": "Lesen",
|
"ButtonRead": "Lesen",
|
||||||
"ButtonReadLess": "Weniger anzeigen",
|
"ButtonReadLess": "weniger Anzeigen",
|
||||||
"ButtonReadMore": "Mehr anzeigen",
|
"ButtonReadMore": "Mehr Anzeigen",
|
||||||
"ButtonRefresh": "Neu Laden",
|
"ButtonRefresh": "Neu Laden",
|
||||||
"ButtonRemove": "Entfernen",
|
"ButtonRemove": "Entfernen",
|
||||||
"ButtonRemoveAll": "Alles entfernen",
|
"ButtonRemoveAll": "Alles entfernen",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Benachrichtigung bearbeiten",
|
"HeaderNotificationUpdate": "Benachrichtigung bearbeiten",
|
||||||
"HeaderNotifications": "Benachrichtigungen",
|
"HeaderNotifications": "Benachrichtigungen",
|
||||||
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
|
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
|
||||||
|
"HeaderOpenListeningSessions": "Aktive Hörbuch-Sitzungen",
|
||||||
"HeaderOpenRSSFeed": "RSS-Feed öffnen",
|
"HeaderOpenRSSFeed": "RSS-Feed öffnen",
|
||||||
"HeaderOtherFiles": "Sonstige Dateien",
|
"HeaderOtherFiles": "Sonstige Dateien",
|
||||||
"HeaderPasswordAuthentication": "Passwortauthentifizierung",
|
"HeaderPasswordAuthentication": "Passwortauthentifizierung",
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Entferne {0} Episoden",
|
"HeaderRemoveEpisodes": "Entferne {0} Episoden",
|
||||||
"HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte",
|
"HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte",
|
||||||
"HeaderSchedule": "Zeitplan",
|
"HeaderSchedule": "Zeitplan",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Automatische Episoden-Downloads planen",
|
||||||
"HeaderScheduleLibraryScans": "Automatische Bibliotheksscans",
|
"HeaderScheduleLibraryScans": "Automatische Bibliotheksscans",
|
||||||
"HeaderSession": "Sitzung",
|
"HeaderSession": "Sitzung",
|
||||||
"HeaderSetBackupSchedule": "Zeitplan für die Datensicherung festlegen",
|
"HeaderSetBackupSchedule": "Zeitplan für die Datensicherung festlegen",
|
||||||
@@ -218,13 +220,14 @@
|
|||||||
"LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen",
|
"LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen",
|
||||||
"LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu",
|
"LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu",
|
||||||
"LabelAddedAt": "Hinzugefügt am",
|
"LabelAddedAt": "Hinzugefügt am",
|
||||||
"LabelAddedDate": "Hinzugefügt {0}",
|
"LabelAddedDate": "{0} Hinzugefügt",
|
||||||
"LabelAdminUsersOnly": "Nur Admin Benutzer",
|
"LabelAdminUsersOnly": "Nur Admin Benutzer",
|
||||||
"LabelAll": "Alle",
|
"LabelAll": "Alle",
|
||||||
"LabelAllUsers": "Alle Benutzer",
|
"LabelAllUsers": "Alle Benutzer",
|
||||||
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
|
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
|
||||||
"LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste",
|
"LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste",
|
||||||
"LabelAlreadyInYourLibrary": "Bereits in der Bibliothek",
|
"LabelAlreadyInYourLibrary": "Bereits in der Bibliothek",
|
||||||
|
"LabelApiToken": "API Schlüssel",
|
||||||
"LabelAppend": "Anhängen",
|
"LabelAppend": "Anhängen",
|
||||||
"LabelAudioBitrate": "Audiobitrate (z. B. 128 kbit/s)",
|
"LabelAudioBitrate": "Audiobitrate (z. B. 128 kbit/s)",
|
||||||
"LabelAudioChannels": "Audiokanäle (1 oder 2)",
|
"LabelAudioChannels": "Audiokanäle (1 oder 2)",
|
||||||
@@ -250,15 +253,18 @@
|
|||||||
"LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen",
|
"LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen",
|
||||||
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn du bereits mehrere Sicherungen als die definierte max. Anzahl hast, solltest du diese manuell entfernen.",
|
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn du bereits mehrere Sicherungen als die definierte max. Anzahl hast, solltest du diese manuell entfernen.",
|
||||||
"LabelBitrate": "Bitrate",
|
"LabelBitrate": "Bitrate",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Bücher",
|
"LabelBooks": "Bücher",
|
||||||
"LabelButtonText": "Knopftext",
|
"LabelButtonText": "Knopftext",
|
||||||
"LabelByAuthor": "von {0}",
|
"LabelByAuthor": "von {0}",
|
||||||
"LabelChangePassword": "Passwort ändern",
|
"LabelChangePassword": "Passwort ändern",
|
||||||
"LabelChannels": "Kanäle",
|
"LabelChannels": "Kanäle",
|
||||||
|
"LabelChapterCount": "{0} Kapitel",
|
||||||
"LabelChapterTitle": "Kapitelüberschrift",
|
"LabelChapterTitle": "Kapitelüberschrift",
|
||||||
"LabelChapters": "Kapitel",
|
"LabelChapters": "Kapitel",
|
||||||
"LabelChaptersFound": "Gefundene Kapitel",
|
"LabelChaptersFound": "Gefundene Kapitel",
|
||||||
"LabelClickForMoreInfo": "Klicken für mehr Informationen",
|
"LabelClickForMoreInfo": "Klicken für mehr Informationen",
|
||||||
|
"LabelClickToUseCurrentValue": "Anklicken um aktuellen Wert zu verwenden",
|
||||||
"LabelClosePlayer": "Player schließen",
|
"LabelClosePlayer": "Player schließen",
|
||||||
"LabelCodec": "Codec",
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Serien einklappen",
|
"LabelCollapseSeries": "Serien einklappen",
|
||||||
@@ -316,12 +322,17 @@
|
|||||||
"LabelEncodingStartedNavigation": "Sobald die Aufgabe gestartet ist, kann die Seite verlassen werden.",
|
"LabelEncodingStartedNavigation": "Sobald die Aufgabe gestartet ist, kann die Seite verlassen werden.",
|
||||||
"LabelEncodingTimeWarning": "Kodierung kann bis zu 30 Minuten dauern.",
|
"LabelEncodingTimeWarning": "Kodierung kann bis zu 30 Minuten dauern.",
|
||||||
"LabelEncodingWarningAdvancedSettings": "Achtung: Ändere diese Einstellungen nur, wenn du dich mit ffmpeg Kodierung auskennst.",
|
"LabelEncodingWarningAdvancedSettings": "Achtung: Ändere diese Einstellungen nur, wenn du dich mit ffmpeg Kodierung auskennst.",
|
||||||
|
"LabelEncodingWatcherDisabled": "Wenn der Watcher deaktiviert ist musst du das Hörbuch danach erneut scannen.",
|
||||||
"LabelEnd": "Ende",
|
"LabelEnd": "Ende",
|
||||||
"LabelEndOfChapter": "Ende des Kapitels",
|
"LabelEndOfChapter": "Ende des Kapitels",
|
||||||
"LabelEpisode": "Episode",
|
"LabelEpisode": "Episode",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Episode nicht mit RSS-Feed verknüpft",
|
||||||
|
"LabelEpisodeNumber": "Episode #{0}",
|
||||||
"LabelEpisodeTitle": "Episodentitel",
|
"LabelEpisodeTitle": "Episodentitel",
|
||||||
"LabelEpisodeType": "Episodentyp",
|
"LabelEpisodeType": "Episodentyp",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "Episoden URL vom RSS-Feed",
|
||||||
"LabelEpisodes": "Episoden",
|
"LabelEpisodes": "Episoden",
|
||||||
|
"LabelEpisodic": "Episodisch",
|
||||||
"LabelExample": "Beispiel",
|
"LabelExample": "Beispiel",
|
||||||
"LabelExpandSeries": "Serie ausklappen",
|
"LabelExpandSeries": "Serie ausklappen",
|
||||||
"LabelExpandSubSeries": "Unterserie ausklappen",
|
"LabelExpandSubSeries": "Unterserie ausklappen",
|
||||||
@@ -349,6 +360,7 @@
|
|||||||
"LabelFontScale": "Schriftgröße",
|
"LabelFontScale": "Schriftgröße",
|
||||||
"LabelFontStrikethrough": "Durchgestrichen",
|
"LabelFontStrikethrough": "Durchgestrichen",
|
||||||
"LabelFormat": "Format",
|
"LabelFormat": "Format",
|
||||||
|
"LabelFull": "Voll",
|
||||||
"LabelGenre": "Kategorie",
|
"LabelGenre": "Kategorie",
|
||||||
"LabelGenres": "Kategorien",
|
"LabelGenres": "Kategorien",
|
||||||
"LabelHardDeleteFile": "Datei dauerhaft löschen",
|
"LabelHardDeleteFile": "Datei dauerhaft löschen",
|
||||||
@@ -404,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "Niedrigste Priorität",
|
"LabelLowestPriority": "Niedrigste Priorität",
|
||||||
"LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit",
|
"LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit",
|
||||||
"LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID vom SSO-Anbieter zugeordnet",
|
"LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID vom SSO-Anbieter zugeordnet",
|
||||||
|
"LabelMaxEpisodesToDownload": "Max. Anzahl an Episoden zum Herunterladen, 0 für unbegrenzte Episoden.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Max. Anzahl neuer Episoden zum Herunterladen pro Abfrage",
|
||||||
|
"LabelMaxEpisodesToKeep": "Max. Anzahl zu behaltender Episoden",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "0 setzt keine Begrenzung. Wenn eine neue Episode automatisch heruntergeladen wird, wird die älteste Episode gelöscht, wenn du mehr als X Episoden gespeichert hast. Es wird nur eine Episode pro neuem Download gelöscht.",
|
||||||
"LabelMediaPlayer": "Mediaplayer",
|
"LabelMediaPlayer": "Mediaplayer",
|
||||||
"LabelMediaType": "Medientyp",
|
"LabelMediaType": "Medientyp",
|
||||||
"LabelMetaTag": "Meta Schlagwort",
|
"LabelMetaTag": "Meta Schlagwort",
|
||||||
@@ -449,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Name des OpenID-Claims, der eine Liste der Benutzergruppen enthält. Wird häufig als <code>groups</code> bezeichnet. <b>Wenn konfiguriert</b>, wird die Anwendung automatisch Rollen basierend auf den Gruppenmitgliedschaften des Benutzers zuweisen, vorausgesetzt, dass diese Gruppen im Claim als 'admin', 'user' oder 'guest' benannt sind (Groß/Kleinschreibung ist irrelevant). Der Claim eine Liste sein, und wenn ein Benutzer mehreren Gruppen angehört, wird die Anwendung die Rolle zuordnen, die dem höchsten Zugriffslevel entspricht. Wenn keine Gruppe übereinstimmt, wird der Zugang verweigert.",
|
"LabelOpenIDGroupClaimDescription": "Name des OpenID-Claims, der eine Liste der Benutzergruppen enthält. Wird häufig als <code>groups</code> bezeichnet. <b>Wenn konfiguriert</b>, wird die Anwendung automatisch Rollen basierend auf den Gruppenmitgliedschaften des Benutzers zuweisen, vorausgesetzt, dass diese Gruppen im Claim als 'admin', 'user' oder 'guest' benannt sind (Groß/Kleinschreibung ist irrelevant). Der Claim eine Liste sein, und wenn ein Benutzer mehreren Gruppen angehört, wird die Anwendung die Rolle zuordnen, die dem höchsten Zugriffslevel entspricht. Wenn keine Gruppe übereinstimmt, wird der Zugang verweigert.",
|
||||||
"LabelOpenRSSFeed": "Öffne RSS-Feed",
|
"LabelOpenRSSFeed": "Öffne RSS-Feed",
|
||||||
"LabelOverwrite": "Überschreiben",
|
"LabelOverwrite": "Überschreiben",
|
||||||
|
"LabelPaginationPageXOfY": "Seite {0} von {1}",
|
||||||
"LabelPassword": "Passwort",
|
"LabelPassword": "Passwort",
|
||||||
"LabelPath": "Pfad",
|
"LabelPath": "Pfad",
|
||||||
"LabelPermanent": "Dauerhaft",
|
"LabelPermanent": "Dauerhaft",
|
||||||
"LabelPermissionsAccessAllLibraries": "Zugriff auf alle Bibliotheken",
|
"LabelPermissionsAccessAllLibraries": "Zugriff auf alle Bibliotheken",
|
||||||
"LabelPermissionsAccessAllTags": "Zugriff auf alle Schlagwörter",
|
"LabelPermissionsAccessAllTags": "Zugriff auf alle Schlagwörter",
|
||||||
"LabelPermissionsAccessExplicitContent": "Zugriff auf explizite (alterbeschränkte) Inhalte",
|
"LabelPermissionsAccessExplicitContent": "Zugriff auf explizite (alterbeschränkte) Inhalte",
|
||||||
|
"LabelPermissionsCreateEreader": "Kann E-Reader erstellen",
|
||||||
"LabelPermissionsDelete": "Darf Löschen",
|
"LabelPermissionsDelete": "Darf Löschen",
|
||||||
"LabelPermissionsDownload": "Herunterladen",
|
"LabelPermissionsDownload": "Herunterladen",
|
||||||
"LabelPermissionsUpdate": "Aktualisieren",
|
"LabelPermissionsUpdate": "Aktualisieren",
|
||||||
@@ -499,18 +517,24 @@
|
|||||||
"LabelRedo": "Wiederholen",
|
"LabelRedo": "Wiederholen",
|
||||||
"LabelRegion": "Region",
|
"LabelRegion": "Region",
|
||||||
"LabelReleaseDate": "Veröffentlichungsdatum",
|
"LabelReleaseDate": "Veröffentlichungsdatum",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Alle metadata.abs Dateien löschen",
|
||||||
|
"LabelRemoveAllMetadataJson": "Alle metadata.json Dateien löschen",
|
||||||
"LabelRemoveCover": "Entferne Titelbild",
|
"LabelRemoveCover": "Entferne Titelbild",
|
||||||
|
"LabelRemoveMetadataFile": "Metadaten-Dateien in Bibliotheksordnern löschen",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Alle metadata.json und metadata.abs Dateien aus den Ordnern {0} löschen.",
|
||||||
"LabelRowsPerPage": "Zeilen pro Seite",
|
"LabelRowsPerPage": "Zeilen pro Seite",
|
||||||
"LabelSearchTerm": "Begriff suchen",
|
"LabelSearchTerm": "Begriff suchen",
|
||||||
"LabelSearchTitle": "Titel suchen",
|
"LabelSearchTitle": "Titel suchen",
|
||||||
"LabelSearchTitleOrASIN": "Titel oder ASIN suchen",
|
"LabelSearchTitleOrASIN": "Titel oder ASIN suchen",
|
||||||
"LabelSeason": "Staffel",
|
"LabelSeason": "Staffel",
|
||||||
|
"LabelSeasonNumber": "Staffel #{0}",
|
||||||
"LabelSelectAll": "Alles auswählen",
|
"LabelSelectAll": "Alles auswählen",
|
||||||
"LabelSelectAllEpisodes": "Alle Episoden auswählen",
|
"LabelSelectAllEpisodes": "Alle Episoden auswählen",
|
||||||
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
|
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
|
||||||
"LabelSelectUsers": "Benutzer auswählen",
|
"LabelSelectUsers": "Benutzer auswählen",
|
||||||
"LabelSendEbookToDevice": "E-Buch senden an …",
|
"LabelSendEbookToDevice": "E-Buch senden an …",
|
||||||
"LabelSequence": "Reihenfolge",
|
"LabelSequence": "Reihenfolge",
|
||||||
|
"LabelSerial": "fortlaufend",
|
||||||
"LabelSeries": "Serien",
|
"LabelSeries": "Serien",
|
||||||
"LabelSeriesName": "Serienname",
|
"LabelSeriesName": "Serienname",
|
||||||
"LabelSeriesProgress": "Serienfortschritt",
|
"LabelSeriesProgress": "Serienfortschritt",
|
||||||
@@ -539,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Serien, die nur ein einzelnes Buch enthalten, werden auf der Startseite und in der Serienansicht ausgeblendet.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Serien, die nur ein einzelnes Buch enthalten, werden auf der Startseite und in der Serienansicht ausgeblendet.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht",
|
"LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht",
|
||||||
"LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht",
|
"LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "In Prozent gehört größer als",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Verbleibende Zeit ist weniger als (Sekunden)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Markiere Mediendateien als fertig, wenn",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Überspringe vorherige Bücher in fortführender Serie",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Überspringe vorherige Bücher in fortführender Serie",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Die Startseite von \"Fortführende Serien\" zeigt das erste noch nicht begonnene Buch in Serien an, die mindestens ein Buch abgeschlossen und keine Bücher begonnen haben. Wenn diese Einstellung aktiviert wird, werden Serien ab dem letzten abgeschlossenen Buch fortgesetzt und nicht ab dem ersten nicht begonnenen Buch.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Die Startseite von \"Fortführende Serien\" zeigt das erste noch nicht begonnene Buch in Serien an, die mindestens ein Buch abgeschlossen und keine Bücher begonnen haben. Wenn diese Einstellung aktiviert wird, werden Serien ab dem letzten abgeschlossenen Buch fortgesetzt und nicht ab dem ersten nicht begonnenen Buch.",
|
||||||
"LabelSettingsParseSubtitles": "Analysiere Untertitel",
|
"LabelSettingsParseSubtitles": "Analysiere Untertitel",
|
||||||
@@ -557,7 +584,7 @@
|
|||||||
"LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet",
|
"LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet",
|
||||||
"LabelSettingsTimeFormat": "Zeitformat",
|
"LabelSettingsTimeFormat": "Zeitformat",
|
||||||
"LabelShare": "Freigeben",
|
"LabelShare": "Freigeben",
|
||||||
"LabelShareOpen": "Freigabe",
|
"LabelShareOpen": "Freigeben",
|
||||||
"LabelShareURL": "Freigabe URL",
|
"LabelShareURL": "Freigabe URL",
|
||||||
"LabelShowAll": "Alles anzeigen",
|
"LabelShowAll": "Alles anzeigen",
|
||||||
"LabelShowSeconds": "Zeige Sekunden",
|
"LabelShowSeconds": "Zeige Sekunden",
|
||||||
@@ -603,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} Minuten",
|
"LabelTimeDurationXMinutes": "{0} Minuten",
|
||||||
"LabelTimeDurationXSeconds": "{0} Sekunden",
|
"LabelTimeDurationXSeconds": "{0} Sekunden",
|
||||||
"LabelTimeInMinutes": "Zeit in Minuten",
|
"LabelTimeInMinutes": "Zeit in Minuten",
|
||||||
|
"LabelTimeLeft": "{0} verbleibend",
|
||||||
"LabelTimeListened": "Gehörte Zeit",
|
"LabelTimeListened": "Gehörte Zeit",
|
||||||
"LabelTimeListenedToday": "Heute gehörte Zeit",
|
"LabelTimeListenedToday": "Heute gehörte Zeit",
|
||||||
"LabelTimeRemaining": "{0} verbleibend",
|
"LabelTimeRemaining": "{0} verbleibend",
|
||||||
@@ -623,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "Mehrfachdatei",
|
"LabelTracksMultiTrack": "Mehrfachdatei",
|
||||||
"LabelTracksNone": "Keine Dateien",
|
"LabelTracksNone": "Keine Dateien",
|
||||||
"LabelTracksSingleTrack": "Einzeldatei",
|
"LabelTracksSingleTrack": "Einzeldatei",
|
||||||
|
"LabelTrailer": "Vorschau",
|
||||||
"LabelType": "Typ",
|
"LabelType": "Typ",
|
||||||
"LabelUnabridged": "Ungekürzt",
|
"LabelUnabridged": "Ungekürzt",
|
||||||
"LabelUndo": "Rückgängig machen",
|
"LabelUndo": "Rückgängig machen",
|
||||||
@@ -634,11 +663,13 @@
|
|||||||
"LabelUpdateDetailsHelp": "Erlaube das Überschreiben bestehender Details für die ausgewählten Hörbücher, wenn eine Übereinstimmung gefunden wird",
|
"LabelUpdateDetailsHelp": "Erlaube das Überschreiben bestehender Details für die ausgewählten Hörbücher, wenn eine Übereinstimmung gefunden wird",
|
||||||
"LabelUpdatedAt": "Aktualisiert am",
|
"LabelUpdatedAt": "Aktualisiert am",
|
||||||
"LabelUploaderDragAndDrop": "Ziehen und Ablegen von Dateien oder Ordnern",
|
"LabelUploaderDragAndDrop": "Ziehen und Ablegen von Dateien oder Ordnern",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Dateien per Drag & Drop hierher ziehen",
|
||||||
"LabelUploaderDropFiles": "Dateien löschen",
|
"LabelUploaderDropFiles": "Dateien löschen",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Automatisches Aktualisieren von Titel, Autor und Serie",
|
"LabelUploaderItemFetchMetadataHelp": "Automatisches Aktualisieren von Titel, Autor und Serie",
|
||||||
"LabelUseAdvancedOptions": "Nutze Erweiterte Optionen",
|
"LabelUseAdvancedOptions": "Nutze Erweiterte Optionen",
|
||||||
"LabelUseChapterTrack": "Kapiteldatei verwenden",
|
"LabelUseChapterTrack": "Kapiteldatei verwenden",
|
||||||
"LabelUseFullTrack": "Gesamte Datei verwenden",
|
"LabelUseFullTrack": "Gesamte Datei verwenden",
|
||||||
|
"LabelUseZeroForUnlimited": "0 für unbegrenzt",
|
||||||
"LabelUser": "Benutzer",
|
"LabelUser": "Benutzer",
|
||||||
"LabelUsername": "Benutzername",
|
"LabelUsername": "Benutzername",
|
||||||
"LabelValue": "Wert",
|
"LabelValue": "Wert",
|
||||||
@@ -648,11 +679,13 @@
|
|||||||
"LabelViewPlayerSettings": "Zeige player Einstellungen",
|
"LabelViewPlayerSettings": "Zeige player Einstellungen",
|
||||||
"LabelViewQueue": "Player-Warteschlange anzeigen",
|
"LabelViewQueue": "Player-Warteschlange anzeigen",
|
||||||
"LabelVolume": "Lautstärke",
|
"LabelVolume": "Lautstärke",
|
||||||
|
"LabelWebRedirectURLsDescription": "Autorisieren Sie diese URLs bei ihrem OAuth-Anbieter, um die Weiterleitung zurück zur Webanwendung nach dem Login zu ermöglichen:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Unterordner für Weiterleitung-URLs",
|
||||||
"LabelWeekdaysToRun": "Wochentage für die Ausführung",
|
"LabelWeekdaysToRun": "Wochentage für die Ausführung",
|
||||||
"LabelXBooks": "{0} Bücher",
|
"LabelXBooks": "{0} Bücher",
|
||||||
"LabelXItems": "{0} Medien",
|
"LabelXItems": "{0} Medien",
|
||||||
"LabelYearReviewHide": "Verstecke Jahr in Übersicht",
|
"LabelYearReviewHide": "Jahresrückblick verbergen",
|
||||||
"LabelYearReviewShow": "Zeige Jahr in Übersicht",
|
"LabelYearReviewShow": "Jahresrückblick anzeigen",
|
||||||
"LabelYourAudiobookDuration": "Laufzeit deines Mediums",
|
"LabelYourAudiobookDuration": "Laufzeit deines Mediums",
|
||||||
"LabelYourBookmarks": "Lesezeichen",
|
"LabelYourBookmarks": "Lesezeichen",
|
||||||
"LabelYourPlaylists": "Eigene Wiedergabelisten",
|
"LabelYourPlaylists": "Eigene Wiedergabelisten",
|
||||||
@@ -697,6 +730,7 @@
|
|||||||
"MessageConfirmPurgeCache": "Cache leeren wird das ganze Verzeichnis <code>/metadata/cache</code> löschen. <br /><br />Bist du dir sicher, dass das Cache Verzeichnis gelöscht werden soll?",
|
"MessageConfirmPurgeCache": "Cache leeren wird das ganze Verzeichnis <code>/metadata/cache</code> löschen. <br /><br />Bist du dir sicher, dass das Cache Verzeichnis gelöscht werden soll?",
|
||||||
"MessageConfirmPurgeItemsCache": "Durch Elementcache leeren wird das gesamte Verzeichnis unter <code>/metadata/cache/items</code> gelöscht.<br />Bist du dir sicher?",
|
"MessageConfirmPurgeItemsCache": "Durch Elementcache leeren wird das gesamte Verzeichnis unter <code>/metadata/cache/items</code> gelöscht.<br />Bist du dir sicher?",
|
||||||
"MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achte darauf, dass du eine Sicherungskopie der Audiodateien besitzt. <br><br>Möchtest du fortfahren?",
|
"MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achte darauf, dass du eine Sicherungskopie der Audiodateien besitzt. <br><br>Möchtest du fortfahren?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "Schnellabgleich von Episoden überschreibt deren Details, wenn ein passender Eintrag gefunden wurde, wird aber nur auf bisher unbearbeitete Episoden angewendet. Wirklich fortfahren?",
|
||||||
"MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Bist du dir sicher?",
|
"MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Bist du dir sicher?",
|
||||||
"MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?",
|
"MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?",
|
||||||
"MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?",
|
"MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?",
|
||||||
@@ -704,6 +738,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "Episode \"{0}\" wird entfernt! Bist du dir sicher?",
|
"MessageConfirmRemoveEpisode": "Episode \"{0}\" wird entfernt! Bist du dir sicher?",
|
||||||
"MessageConfirmRemoveEpisodes": "{0} Episoden werden entfernt! Bist du dir sicher?",
|
"MessageConfirmRemoveEpisodes": "{0} Episoden werden entfernt! Bist du dir sicher?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Bist du dir sicher, dass du {0} Hörsitzungen enfernen möchtest?",
|
"MessageConfirmRemoveListeningSessions": "Bist du dir sicher, dass du {0} Hörsitzungen enfernen möchtest?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Bist du sicher, dass du alle metadata.{0} Dateien in deinen Bibliotheksordnern löschen willst?",
|
||||||
"MessageConfirmRemoveNarrator": "Erzähler \"{0}\" wird entfernt! Bist du dir sicher?",
|
"MessageConfirmRemoveNarrator": "Erzähler \"{0}\" wird entfernt! Bist du dir sicher?",
|
||||||
"MessageConfirmRemovePlaylist": "Wiedergabeliste \"{0}\" wird entfernt! Bist du dir sicher?",
|
"MessageConfirmRemovePlaylist": "Wiedergabeliste \"{0}\" wird entfernt! Bist du dir sicher?",
|
||||||
"MessageConfirmRenameGenre": "Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Bist du dir sicher?",
|
"MessageConfirmRenameGenre": "Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Bist du dir sicher?",
|
||||||
@@ -719,6 +754,7 @@
|
|||||||
"MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge",
|
"MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge",
|
||||||
"MessageEmbedFailed": "Einbetten fehlgeschlagen!",
|
"MessageEmbedFailed": "Einbetten fehlgeschlagen!",
|
||||||
"MessageEmbedFinished": "Einbettung abgeschlossen!",
|
"MessageEmbedFinished": "Einbettung abgeschlossen!",
|
||||||
|
"MessageEmbedQueue": "Eingereiht zum einbinden von Metadaten ({0} in Warteschlange)",
|
||||||
"MessageEpisodesQueuedForDownload": "{0} Episode(n) in der Warteschlange zum Herunterladen",
|
"MessageEpisodesQueuedForDownload": "{0} Episode(n) in der Warteschlange zum Herunterladen",
|
||||||
"MessageEreaderDevices": "Um die Zustellung von E-Büchern sicherzustellen, musst du eventuell die oben genannte E-Mail-Adresse als gültigen Absender für jedes unten aufgeführte Gerät hinzufügen.",
|
"MessageEreaderDevices": "Um die Zustellung von E-Büchern sicherzustellen, musst du eventuell die oben genannte E-Mail-Adresse als gültigen Absender für jedes unten aufgeführte Gerät hinzufügen.",
|
||||||
"MessageFeedURLWillBe": "Feed-URL wird {0} sein",
|
"MessageFeedURLWillBe": "Feed-URL wird {0} sein",
|
||||||
@@ -780,6 +816,10 @@
|
|||||||
"MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung",
|
"MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung",
|
||||||
"MessagePleaseWait": "Bitte warten...",
|
"MessagePleaseWait": "Bitte warten...",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "Der Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann",
|
"MessagePodcastHasNoRSSFeedForMatching": "Der Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann",
|
||||||
|
"MessagePodcastSearchField": "Suchbegriff oder RSS-Feed URL eingeben",
|
||||||
|
"MessageQuickEmbedInProgress": "Schnellabgleich läuft",
|
||||||
|
"MessageQuickEmbedQueue": "In Warteschlange für Schnelles einbinden ({0} eingereiht)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Quick Match aller Episoden",
|
||||||
"MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.",
|
"MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.",
|
||||||
"MessageRemoveChapter": "Kapitel entfernen",
|
"MessageRemoveChapter": "Kapitel entfernen",
|
||||||
"MessageRemoveEpisodes": "Entferne {0} Episode(n)",
|
"MessageRemoveEpisodes": "Entferne {0} Episode(n)",
|
||||||
@@ -795,7 +835,7 @@
|
|||||||
"MessageSetChaptersFromTracksDescription": "Kaitelerstellung basiert auf den existierenden einzelnen Audiodateien. Pro existierende Audiodatei wird 1 Kapitel erstellt, wobei deren Kapitelname aus dem Audiodateinamen extrahiert wird",
|
"MessageSetChaptersFromTracksDescription": "Kaitelerstellung basiert auf den existierenden einzelnen Audiodateien. Pro existierende Audiodatei wird 1 Kapitel erstellt, wobei deren Kapitelname aus dem Audiodateinamen extrahiert wird",
|
||||||
"MessageShareExpirationWillBe": "Läuft am <strong>{0}</strong> ab",
|
"MessageShareExpirationWillBe": "Läuft am <strong>{0}</strong> ab",
|
||||||
"MessageShareExpiresIn": "Läuft in {0} ab",
|
"MessageShareExpiresIn": "Läuft in {0} ab",
|
||||||
"MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein.",
|
"MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein",
|
||||||
"MessageStartPlaybackAtTime": "Start der Wiedergabe für \"{0}\" bei {1}?",
|
"MessageStartPlaybackAtTime": "Start der Wiedergabe für \"{0}\" bei {1}?",
|
||||||
"MessageTaskAudioFileNotWritable": "Die Audiodatei \"{0}\" ist schreibgeschützt",
|
"MessageTaskAudioFileNotWritable": "Die Audiodatei \"{0}\" ist schreibgeschützt",
|
||||||
"MessageTaskCanceledByUser": "Aufgabe vom Benutzer abgebrochen",
|
"MessageTaskCanceledByUser": "Aufgabe vom Benutzer abgebrochen",
|
||||||
@@ -822,6 +862,9 @@
|
|||||||
"MessageTaskOpmlImportFeedPodcastExists": "Der Podcast ist bereits im Pfad vorhanden",
|
"MessageTaskOpmlImportFeedPodcastExists": "Der Podcast ist bereits im Pfad vorhanden",
|
||||||
"MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen",
|
"MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen",
|
||||||
"MessageTaskOpmlImportFinished": "{0} Podcasts hinzugefügt",
|
"MessageTaskOpmlImportFinished": "{0} Podcasts hinzugefügt",
|
||||||
|
"MessageTaskOpmlParseFailed": "Fehler beim lesen der OPML Datei",
|
||||||
|
"MessageTaskOpmlParseFastFail": "Ungültie OPML Datei: <opml> ODER <outline> tag wurde nicht gefunden",
|
||||||
|
"MessageTaskOpmlParseNoneFound": "Keine feeds in der OPML Datei gefunden",
|
||||||
"MessageTaskScanItemsAdded": "{0} hinzugefügt",
|
"MessageTaskScanItemsAdded": "{0} hinzugefügt",
|
||||||
"MessageTaskScanItemsMissing": "{0} fehlend",
|
"MessageTaskScanItemsMissing": "{0} fehlend",
|
||||||
"MessageTaskScanItemsUpdated": "{0} aktualisiert",
|
"MessageTaskScanItemsUpdated": "{0} aktualisiert",
|
||||||
@@ -846,6 +889,10 @@
|
|||||||
"NoteUploaderFoldersWithMediaFiles": "Ordner mit Mediendateien werden als separate Bibliothekselemente behandelt.",
|
"NoteUploaderFoldersWithMediaFiles": "Ordner mit Mediendateien werden als separate Bibliothekselemente behandelt.",
|
||||||
"NoteUploaderOnlyAudioFiles": "Wenn du nur Audiodateien hochlädst, wird jede Audiodatei als ein separates Medium behandelt.",
|
"NoteUploaderOnlyAudioFiles": "Wenn du nur Audiodateien hochlädst, wird jede Audiodatei als ein separates Medium behandelt.",
|
||||||
"NoteUploaderUnsupportedFiles": "Nicht unterstützte Dateien werden ignoriert. Bei der Auswahl oder dem Löschen eines Ordners werden andere Dateien, die sich nicht in einem Elementordner befinden, ignoriert.",
|
"NoteUploaderUnsupportedFiles": "Nicht unterstützte Dateien werden ignoriert. Bei der Auswahl oder dem Löschen eines Ordners werden andere Dateien, die sich nicht in einem Elementordner befinden, ignoriert.",
|
||||||
|
"NotificationOnBackupCompletedDescription": "Wird ausgeführt wenn ein Backup erstellt wurde",
|
||||||
|
"NotificationOnBackupFailedDescription": "Wird ausgeführt wenn ein Backup fehlgeschlagen ist",
|
||||||
|
"NotificationOnEpisodeDownloadedDescription": "Wird ausgeführt wenn eine Podcast Folge automatisch heruntergeladen wird",
|
||||||
|
"NotificationOnTestDescription": "Wird ausgeführt wenn das Benachrichtigungssystem getestet wird",
|
||||||
"PlaceholderNewCollection": "Neuer Sammlungsname",
|
"PlaceholderNewCollection": "Neuer Sammlungsname",
|
||||||
"PlaceholderNewFolderPath": "Neuer Ordnerpfad",
|
"PlaceholderNewFolderPath": "Neuer Ordnerpfad",
|
||||||
"PlaceholderNewPlaylist": "Neuer Wiedergabelistenname",
|
"PlaceholderNewPlaylist": "Neuer Wiedergabelistenname",
|
||||||
@@ -871,6 +918,7 @@
|
|||||||
"StatsYearInReview": "DAS JAHR IM RÜCKBLICK",
|
"StatsYearInReview": "DAS JAHR IM RÜCKBLICK",
|
||||||
"ToastAccountUpdateSuccess": "Konto aktualisiert",
|
"ToastAccountUpdateSuccess": "Konto aktualisiert",
|
||||||
"ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig",
|
"ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig",
|
||||||
|
"ToastAsinRequired": "ASIN ist erforderlich",
|
||||||
"ToastAuthorImageRemoveSuccess": "Autorenbild entfernt",
|
"ToastAuthorImageRemoveSuccess": "Autorenbild entfernt",
|
||||||
"ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden",
|
"ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden",
|
||||||
"ToastAuthorRemoveSuccess": "Autor entfernt",
|
"ToastAuthorRemoveSuccess": "Autor entfernt",
|
||||||
@@ -890,6 +938,8 @@
|
|||||||
"ToastBackupUploadSuccess": "Sicherung hochgeladen",
|
"ToastBackupUploadSuccess": "Sicherung hochgeladen",
|
||||||
"ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen",
|
"ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen",
|
||||||
"ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich",
|
"ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich",
|
||||||
|
"ToastBatchQuickMatchFailed": "Batch-Schnellabgleich fehlgeschlagen!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Batch-Schnellabgleich für {0} Bücher gestartet!",
|
||||||
"ToastBatchUpdateFailed": "Stapelaktualisierung fehlgeschlagen",
|
"ToastBatchUpdateFailed": "Stapelaktualisierung fehlgeschlagen",
|
||||||
"ToastBatchUpdateSuccess": "Stapelaktualisierung erfolgreich",
|
"ToastBatchUpdateSuccess": "Stapelaktualisierung erfolgreich",
|
||||||
"ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden",
|
"ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden",
|
||||||
@@ -901,6 +951,7 @@
|
|||||||
"ToastChaptersHaveErrors": "Kapitel sind fehlerhaft",
|
"ToastChaptersHaveErrors": "Kapitel sind fehlerhaft",
|
||||||
"ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen",
|
"ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen",
|
||||||
"ToastChaptersRemoved": "Kapitel entfernt",
|
"ToastChaptersRemoved": "Kapitel entfernt",
|
||||||
|
"ToastChaptersUpdated": "Kapitel aktualisiert",
|
||||||
"ToastCollectionItemsAddFailed": "Das Hinzufügen von Element(en) zur Sammlung ist fehlgeschlagen",
|
"ToastCollectionItemsAddFailed": "Das Hinzufügen von Element(en) zur Sammlung ist fehlgeschlagen",
|
||||||
"ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt",
|
"ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt",
|
"ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt",
|
||||||
@@ -918,11 +969,14 @@
|
|||||||
"ToastEncodeCancelSucces": "Encoding abgebrochen",
|
"ToastEncodeCancelSucces": "Encoding abgebrochen",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "Warteschlange konnte nicht gelöscht werden",
|
"ToastEpisodeDownloadQueueClearFailed": "Warteschlange konnte nicht gelöscht werden",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "Warteschlange für Episoden-Downloads gelöscht",
|
"ToastEpisodeDownloadQueueClearSuccess": "Warteschlange für Episoden-Downloads gelöscht",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} Episoden aktualisiert",
|
||||||
"ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden",
|
"ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden",
|
||||||
"ToastFailedToLoadData": "Daten laden fehlgeschlagen",
|
"ToastFailedToLoadData": "Daten laden fehlgeschlagen",
|
||||||
|
"ToastFailedToMatch": "Fehler beim Abgleich",
|
||||||
"ToastFailedToShare": "Fehler beim Teilen",
|
"ToastFailedToShare": "Fehler beim Teilen",
|
||||||
"ToastFailedToUpdate": "Aktualisierung ist fehlgeschlagen",
|
"ToastFailedToUpdate": "Aktualisierung ist fehlgeschlagen",
|
||||||
"ToastInvalidImageUrl": "Ungültiger Bild URL",
|
"ToastInvalidImageUrl": "Ungültiger Bild URL",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Ungültige Max. Anzahl an Episoden zum Herunterladen",
|
||||||
"ToastInvalidUrl": "Ungültiger URL",
|
"ToastInvalidUrl": "Ungültiger URL",
|
||||||
"ToastItemCoverUpdateSuccess": "Titelbild aktualisiert",
|
"ToastItemCoverUpdateSuccess": "Titelbild aktualisiert",
|
||||||
"ToastItemDeletedFailed": "Fehler beim löschen des Artikels",
|
"ToastItemDeletedFailed": "Fehler beim löschen des Artikels",
|
||||||
@@ -941,14 +995,21 @@
|
|||||||
"ToastLibraryScanStarted": "Bibliotheksscan gestartet",
|
"ToastLibraryScanStarted": "Bibliotheksscan gestartet",
|
||||||
"ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert",
|
"ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert",
|
||||||
"ToastMatchAllAuthorsFailed": "Nicht alle Autoren konnten zugeordnet werden",
|
"ToastMatchAllAuthorsFailed": "Nicht alle Autoren konnten zugeordnet werden",
|
||||||
|
"ToastMetadataFilesRemovedError": "Fehler beim löschen von metadata.{0} Dateien",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "Keine metadata.{0} Dateien in Bibliothek gefunden",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Keine metadata.{0} Dateien gelöscht",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} Datei(en) gelöscht",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Es muss mindestens ein Pfad angegeben werden",
|
||||||
"ToastNameEmailRequired": "Name und E-Mail sind erforderlich",
|
"ToastNameEmailRequired": "Name und E-Mail sind erforderlich",
|
||||||
"ToastNameRequired": "Name ist erforderlich",
|
"ToastNameRequired": "Name ist erforderlich",
|
||||||
|
"ToastNewEpisodesFound": "{0} neue Episoden gefunden",
|
||||||
"ToastNewUserCreatedFailed": "Fehler beim erstellen des Accounts: \"{ 0}\"",
|
"ToastNewUserCreatedFailed": "Fehler beim erstellen des Accounts: \"{ 0}\"",
|
||||||
"ToastNewUserCreatedSuccess": "Neuer Account erstellt",
|
"ToastNewUserCreatedSuccess": "Neuer Account erstellt",
|
||||||
"ToastNewUserLibraryError": "Mindestens eine Bibliothek muss ausgewählt werden",
|
"ToastNewUserLibraryError": "Mindestens eine Bibliothek muss ausgewählt werden",
|
||||||
"ToastNewUserPasswordError": "Passwort erforderlich, nur der root Benutzer darf ein leeres Passwort haben",
|
"ToastNewUserPasswordError": "Passwort erforderlich, nur der root Benutzer darf ein leeres Passwort haben",
|
||||||
"ToastNewUserTagError": "Mindestens ein Tag muss ausgewählt sein",
|
"ToastNewUserTagError": "Mindestens ein Tag muss ausgewählt sein",
|
||||||
"ToastNewUserUsernameError": "Nutzername eingeben",
|
"ToastNewUserUsernameError": "Nutzername eingeben",
|
||||||
|
"ToastNoNewEpisodesFound": "Keine neuen Episoden gefunden",
|
||||||
"ToastNoUpdatesNecessary": "Keine Änderungen nötig",
|
"ToastNoUpdatesNecessary": "Keine Änderungen nötig",
|
||||||
"ToastNotificationCreateFailed": "Fehler beim erstellen der Benachrichtig",
|
"ToastNotificationCreateFailed": "Fehler beim erstellen der Benachrichtig",
|
||||||
"ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung",
|
"ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung",
|
||||||
@@ -967,6 +1028,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast Feeds",
|
"ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast Feeds",
|
||||||
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
|
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
|
||||||
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
|
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
|
||||||
|
"ToastProgressIsNotBeingSynced": "Fortschritt wird nicht synchronisiert, Wiedergabe wird neu gestartet",
|
||||||
"ToastProviderCreatedFailed": "Fehler beim hinzufügen des Anbieters",
|
"ToastProviderCreatedFailed": "Fehler beim hinzufügen des Anbieters",
|
||||||
"ToastProviderCreatedSuccess": "Neuer Anbieter hinzugefügt",
|
"ToastProviderCreatedSuccess": "Neuer Anbieter hinzugefügt",
|
||||||
"ToastProviderNameAndUrlRequired": "Name und URL notwendig",
|
"ToastProviderNameAndUrlRequired": "Name und URL notwendig",
|
||||||
@@ -981,7 +1043,7 @@
|
|||||||
"ToastRenameFailed": "Umbenennen fehlgeschlagen",
|
"ToastRenameFailed": "Umbenennen fehlgeschlagen",
|
||||||
"ToastRescanFailed": "Erneut scannen fehlgeschlagen für {0}",
|
"ToastRescanFailed": "Erneut scannen fehlgeschlagen für {0}",
|
||||||
"ToastRescanRemoved": "Erneut scannen erledigt, Artikel wurde entfernt",
|
"ToastRescanRemoved": "Erneut scannen erledigt, Artikel wurde entfernt",
|
||||||
"ToastRescanUpToDate": "Erneut scannen erledigt, Artikel wahr auf dem neusten Stand",
|
"ToastRescanUpToDate": "Erneut scannen erledigt, Artikel war auf dem neusten Stand",
|
||||||
"ToastRescanUpdated": "Erneut scannen erledigt, Artikel wurde verändert",
|
"ToastRescanUpdated": "Erneut scannen erledigt, Artikel wurde verändert",
|
||||||
"ToastScanFailed": "Fehler beim scannen des Artikels der Bibliothek",
|
"ToastScanFailed": "Fehler beim scannen des Artikels der Bibliothek",
|
||||||
"ToastSelectAtLeastOneUser": "Wähle mindestens einen Benutzer aus",
|
"ToastSelectAtLeastOneUser": "Wähle mindestens einen Benutzer aus",
|
||||||
@@ -993,6 +1055,7 @@
|
|||||||
"ToastSessionCloseFailed": "Fehler beim schließen der Sitzung",
|
"ToastSessionCloseFailed": "Fehler beim schließen der Sitzung",
|
||||||
"ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden",
|
"ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden",
|
||||||
"ToastSessionDeleteSuccess": "Sitzung gelöscht",
|
"ToastSessionDeleteSuccess": "Sitzung gelöscht",
|
||||||
|
"ToastSleepTimerDone": "Einschlaf-Timer aktiviert... zZzzZz",
|
||||||
"ToastSlugMustChange": "URL-Schlüssel enthält ungültige Zeichen",
|
"ToastSlugMustChange": "URL-Schlüssel enthält ungültige Zeichen",
|
||||||
"ToastSlugRequired": "URL-Schlüssel erforderlich",
|
"ToastSlugRequired": "URL-Schlüssel erforderlich",
|
||||||
"ToastSocketConnected": "Verbindung zum WebSocket hergestellt",
|
"ToastSocketConnected": "Verbindung zum WebSocket hergestellt",
|
||||||
|
|||||||
@@ -88,6 +88,8 @@
|
|||||||
"ButtonSaveTracklist": "Save Tracklist",
|
"ButtonSaveTracklist": "Save Tracklist",
|
||||||
"ButtonScan": "Scan",
|
"ButtonScan": "Scan",
|
||||||
"ButtonScanLibrary": "Scan Library",
|
"ButtonScanLibrary": "Scan Library",
|
||||||
|
"ButtonScrollLeft": "Scroll Left",
|
||||||
|
"ButtonScrollRight": "Scroll Right",
|
||||||
"ButtonSearch": "Search",
|
"ButtonSearch": "Search",
|
||||||
"ButtonSelectFolderPath": "Select Folder Path",
|
"ButtonSelectFolderPath": "Select Folder Path",
|
||||||
"ButtonSeries": "Series",
|
"ButtonSeries": "Series",
|
||||||
@@ -163,6 +165,7 @@
|
|||||||
"HeaderNotificationUpdate": "Update Notification",
|
"HeaderNotificationUpdate": "Update Notification",
|
||||||
"HeaderNotifications": "Notifications",
|
"HeaderNotifications": "Notifications",
|
||||||
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
|
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
|
||||||
|
"HeaderOpenListeningSessions": "Open Listening Sessions",
|
||||||
"HeaderOpenRSSFeed": "Open RSS Feed",
|
"HeaderOpenRSSFeed": "Open RSS Feed",
|
||||||
"HeaderOtherFiles": "Other Files",
|
"HeaderOtherFiles": "Other Files",
|
||||||
"HeaderPasswordAuthentication": "Password Authentication",
|
"HeaderPasswordAuthentication": "Password Authentication",
|
||||||
@@ -189,6 +192,7 @@
|
|||||||
"HeaderSettingsExperimental": "Experimental Features",
|
"HeaderSettingsExperimental": "Experimental Features",
|
||||||
"HeaderSettingsGeneral": "General",
|
"HeaderSettingsGeneral": "General",
|
||||||
"HeaderSettingsScanner": "Scanner",
|
"HeaderSettingsScanner": "Scanner",
|
||||||
|
"HeaderSettingsWebClient": "Web Client",
|
||||||
"HeaderSleepTimer": "Sleep Timer",
|
"HeaderSleepTimer": "Sleep Timer",
|
||||||
"HeaderStatsLargestItems": "Largest Items",
|
"HeaderStatsLargestItems": "Largest Items",
|
||||||
"HeaderStatsLongestItems": "Longest Items (hrs)",
|
"HeaderStatsLongestItems": "Longest Items (hrs)",
|
||||||
@@ -226,6 +230,7 @@
|
|||||||
"LabelAllUsersExcludingGuests": "All users excluding guests",
|
"LabelAllUsersExcludingGuests": "All users excluding guests",
|
||||||
"LabelAllUsersIncludingGuests": "All users including guests",
|
"LabelAllUsersIncludingGuests": "All users including guests",
|
||||||
"LabelAlreadyInYourLibrary": "Already in your library",
|
"LabelAlreadyInYourLibrary": "Already in your library",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Append",
|
"LabelAppend": "Append",
|
||||||
"LabelAudioBitrate": "Audio Bitrate (e.g. 128k)",
|
"LabelAudioBitrate": "Audio Bitrate (e.g. 128k)",
|
||||||
"LabelAudioChannels": "Audio Channels (1 or 2)",
|
"LabelAudioChannels": "Audio Channels (1 or 2)",
|
||||||
@@ -463,12 +468,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Name of the OpenID claim that contains a list of the user's groups. Commonly referred to as <code>groups</code>. <b>If configured</b>, the application will automatically assign roles based on the user's group memberships, provided that these groups are named case-insensitively 'admin', 'user', or 'guest' in the claim. The claim should contain a list, and if a user belongs to multiple groups, the application will assign the role corresponding to the highest level of access. If no group matches, access will be denied.",
|
"LabelOpenIDGroupClaimDescription": "Name of the OpenID claim that contains a list of the user's groups. Commonly referred to as <code>groups</code>. <b>If configured</b>, the application will automatically assign roles based on the user's group memberships, provided that these groups are named case-insensitively 'admin', 'user', or 'guest' in the claim. The claim should contain a list, and if a user belongs to multiple groups, the application will assign the role corresponding to the highest level of access. If no group matches, access will be denied.",
|
||||||
"LabelOpenRSSFeed": "Open RSS Feed",
|
"LabelOpenRSSFeed": "Open RSS Feed",
|
||||||
"LabelOverwrite": "Overwrite",
|
"LabelOverwrite": "Overwrite",
|
||||||
|
"LabelPaginationPageXOfY": "Page {0} of {1}",
|
||||||
"LabelPassword": "Password",
|
"LabelPassword": "Password",
|
||||||
"LabelPath": "Path",
|
"LabelPath": "Path",
|
||||||
"LabelPermanent": "Permanent",
|
"LabelPermanent": "Permanent",
|
||||||
"LabelPermissionsAccessAllLibraries": "Can Access All Libraries",
|
"LabelPermissionsAccessAllLibraries": "Can Access All Libraries",
|
||||||
"LabelPermissionsAccessAllTags": "Can Access All Tags",
|
"LabelPermissionsAccessAllTags": "Can Access All Tags",
|
||||||
"LabelPermissionsAccessExplicitContent": "Can Access Explicit Content",
|
"LabelPermissionsAccessExplicitContent": "Can Access Explicit Content",
|
||||||
|
"LabelPermissionsCreateEreader": "Can Create Ereader",
|
||||||
"LabelPermissionsDelete": "Can Delete",
|
"LabelPermissionsDelete": "Can Delete",
|
||||||
"LabelPermissionsDownload": "Can Download",
|
"LabelPermissionsDownload": "Can Download",
|
||||||
"LabelPermissionsUpdate": "Can Update",
|
"LabelPermissionsUpdate": "Can Update",
|
||||||
@@ -538,6 +545,7 @@
|
|||||||
"LabelServerYearReview": "Server Year in Review ({0})",
|
"LabelServerYearReview": "Server Year in Review ({0})",
|
||||||
"LabelSetEbookAsPrimary": "Set as primary",
|
"LabelSetEbookAsPrimary": "Set as primary",
|
||||||
"LabelSetEbookAsSupplementary": "Set as supplementary",
|
"LabelSetEbookAsSupplementary": "Set as supplementary",
|
||||||
|
"LabelSettingsAllowIframe": "Allow embedding in an iframe",
|
||||||
"LabelSettingsAudiobooksOnly": "Audiobooks only",
|
"LabelSettingsAudiobooksOnly": "Audiobooks only",
|
||||||
"LabelSettingsAudiobooksOnlyHelp": "Enabling this setting will ignore ebook files unless they are inside an audiobook folder in which case they will be set as supplementary ebooks",
|
"LabelSettingsAudiobooksOnlyHelp": "Enabling this setting will ignore ebook files unless they are inside an audiobook folder in which case they will be set as supplementary ebooks",
|
||||||
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
|
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
|
||||||
@@ -559,6 +567,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
|
||||||
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Percent complete is greater than",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Time remaining is less than (seconds)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Mark media item as finished when",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.",
|
||||||
"LabelSettingsParseSubtitles": "Parse subtitles",
|
"LabelSettingsParseSubtitles": "Parse subtitles",
|
||||||
@@ -585,6 +596,8 @@
|
|||||||
"LabelSize": "Size",
|
"LabelSize": "Size",
|
||||||
"LabelSleepTimer": "Sleep timer",
|
"LabelSleepTimer": "Sleep timer",
|
||||||
"LabelSlug": "Slug",
|
"LabelSlug": "Slug",
|
||||||
|
"LabelSortAscending": "Ascending",
|
||||||
|
"LabelSortDescending": "Descending",
|
||||||
"LabelStart": "Start",
|
"LabelStart": "Start",
|
||||||
"LabelStartTime": "Start Time",
|
"LabelStartTime": "Start Time",
|
||||||
"LabelStarted": "Started",
|
"LabelStarted": "Started",
|
||||||
@@ -656,6 +669,7 @@
|
|||||||
"LabelUpdateDetailsHelp": "Allow overwriting of existing details for the selected books when a match is located",
|
"LabelUpdateDetailsHelp": "Allow overwriting of existing details for the selected books when a match is located",
|
||||||
"LabelUpdatedAt": "Updated At",
|
"LabelUpdatedAt": "Updated At",
|
||||||
"LabelUploaderDragAndDrop": "Drag & drop files or folders",
|
"LabelUploaderDragAndDrop": "Drag & drop files or folders",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Drag & drop files",
|
||||||
"LabelUploaderDropFiles": "Drop files",
|
"LabelUploaderDropFiles": "Drop files",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Automatically fetch title, author, and series",
|
"LabelUploaderItemFetchMetadataHelp": "Automatically fetch title, author, and series",
|
||||||
"LabelUseAdvancedOptions": "Use Advanced Options",
|
"LabelUseAdvancedOptions": "Use Advanced Options",
|
||||||
@@ -671,6 +685,8 @@
|
|||||||
"LabelViewPlayerSettings": "View player settings",
|
"LabelViewPlayerSettings": "View player settings",
|
||||||
"LabelViewQueue": "View player queue",
|
"LabelViewQueue": "View player queue",
|
||||||
"LabelVolume": "Volume",
|
"LabelVolume": "Volume",
|
||||||
|
"LabelWebRedirectURLsDescription": "Authorize these URLs in your OAuth provider to allow redirection back to the web app after login:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Subfolder for Redirect URLs",
|
||||||
"LabelWeekdaysToRun": "Weekdays to run",
|
"LabelWeekdaysToRun": "Weekdays to run",
|
||||||
"LabelXBooks": "{0} books",
|
"LabelXBooks": "{0} books",
|
||||||
"LabelXItems": "{0} items",
|
"LabelXItems": "{0} items",
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
+51
-8
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ButtonAdd": "Agregar",
|
"ButtonAdd": "Agregaro",
|
||||||
"ButtonAddChapters": "Agregar Capitulo",
|
"ButtonAddChapters": "Agregar",
|
||||||
"ButtonAddDevice": "Agregar Dispositivo",
|
"ButtonAddDevice": "Agregar Dispositivo",
|
||||||
"ButtonAddLibrary": "Crear Biblioteca",
|
"ButtonAddLibrary": "Crear Biblioteca",
|
||||||
"ButtonAddPodcasts": "Agregar Podcasts",
|
"ButtonAddPodcasts": "Agregar Podcasts",
|
||||||
@@ -71,8 +71,8 @@
|
|||||||
"ButtonQuickMatch": "Encontrar Rápido",
|
"ButtonQuickMatch": "Encontrar Rápido",
|
||||||
"ButtonReScan": "Re-Escanear",
|
"ButtonReScan": "Re-Escanear",
|
||||||
"ButtonRead": "Leer",
|
"ButtonRead": "Leer",
|
||||||
"ButtonReadLess": "Lea menos",
|
"ButtonReadLess": "Leer menos",
|
||||||
"ButtonReadMore": "Lea mas",
|
"ButtonReadMore": "Leer más",
|
||||||
"ButtonRefresh": "Refrecar",
|
"ButtonRefresh": "Refrecar",
|
||||||
"ButtonRemove": "Remover",
|
"ButtonRemove": "Remover",
|
||||||
"ButtonRemoveAll": "Remover Todos",
|
"ButtonRemoveAll": "Remover Todos",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Notificación de actualización",
|
"HeaderNotificationUpdate": "Notificación de actualización",
|
||||||
"HeaderNotifications": "Notificaciones",
|
"HeaderNotifications": "Notificaciones",
|
||||||
"HeaderOpenIDConnectAuthentication": "Autenticación OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Autenticación OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Sesiones públicas de escucha",
|
||||||
"HeaderOpenRSSFeed": "Abrir fuente RSS",
|
"HeaderOpenRSSFeed": "Abrir fuente RSS",
|
||||||
"HeaderOtherFiles": "Otros Archivos",
|
"HeaderOtherFiles": "Otros Archivos",
|
||||||
"HeaderPasswordAuthentication": "Autenticación por contraseña",
|
"HeaderPasswordAuthentication": "Autenticación por contraseña",
|
||||||
@@ -219,13 +220,14 @@
|
|||||||
"LabelAddToPlaylist": "Añadido a la lista de reproducción",
|
"LabelAddToPlaylist": "Añadido a la lista de reproducción",
|
||||||
"LabelAddToPlaylistBatch": "Se Añadieron {0} Artículos a la Lista de Reproducción",
|
"LabelAddToPlaylistBatch": "Se Añadieron {0} Artículos a la Lista de Reproducción",
|
||||||
"LabelAddedAt": "Añadido",
|
"LabelAddedAt": "Añadido",
|
||||||
"LabelAddedDate": "Añadido {0}",
|
"LabelAddedDate": "{0} Añadido",
|
||||||
"LabelAdminUsersOnly": "Solamente usuarios administradores",
|
"LabelAdminUsersOnly": "Solamente usuarios administradores",
|
||||||
"LabelAll": "Todos",
|
"LabelAll": "Todos",
|
||||||
"LabelAllUsers": "Todos los Usuarios",
|
"LabelAllUsers": "Todos los Usuarios",
|
||||||
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
|
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
|
||||||
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
|
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
|
||||||
"LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca",
|
"LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca",
|
||||||
|
"LabelApiToken": "Token de la API",
|
||||||
"LabelAppend": "Adjuntar",
|
"LabelAppend": "Adjuntar",
|
||||||
"LabelAudioBitrate": "Tasa de bits del audio (por ejemplo, 128k)",
|
"LabelAudioBitrate": "Tasa de bits del audio (por ejemplo, 128k)",
|
||||||
"LabelAudioChannels": "Canales de audio (1 o 2)",
|
"LabelAudioChannels": "Canales de audio (1 o 2)",
|
||||||
@@ -251,6 +253,7 @@
|
|||||||
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
|
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
|
||||||
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
|
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
|
||||||
"LabelBitrate": "Tasa de bits",
|
"LabelBitrate": "Tasa de bits",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Libros",
|
"LabelBooks": "Libros",
|
||||||
"LabelButtonText": "Texto del botón",
|
"LabelButtonText": "Texto del botón",
|
||||||
"LabelByAuthor": "por {0}",
|
"LabelByAuthor": "por {0}",
|
||||||
@@ -329,6 +332,7 @@
|
|||||||
"LabelEpisodeType": "Tipo de Episodio",
|
"LabelEpisodeType": "Tipo de Episodio",
|
||||||
"LabelEpisodeUrlFromRssFeed": "URL del episodio del feed RSS",
|
"LabelEpisodeUrlFromRssFeed": "URL del episodio del feed RSS",
|
||||||
"LabelEpisodes": "Episodios",
|
"LabelEpisodes": "Episodios",
|
||||||
|
"LabelEpisodic": "Episodios",
|
||||||
"LabelExample": "Ejemplo",
|
"LabelExample": "Ejemplo",
|
||||||
"LabelExpandSeries": "Ampliar serie",
|
"LabelExpandSeries": "Ampliar serie",
|
||||||
"LabelExpandSubSeries": "Expandir la subserie",
|
"LabelExpandSubSeries": "Expandir la subserie",
|
||||||
@@ -413,6 +417,9 @@
|
|||||||
"LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por",
|
"LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por",
|
||||||
"LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO",
|
"LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO",
|
||||||
"LabelMaxEpisodesToDownload": "Número máximo # de episodios para descargar. Usa 0 para descargar una cantidad ilimitada.",
|
"LabelMaxEpisodesToDownload": "Número máximo # de episodios para descargar. Usa 0 para descargar una cantidad ilimitada.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Número máximo de episodios nuevos que se descargarán por comprobación",
|
||||||
|
"LabelMaxEpisodesToKeep": "Número máximo de episodios que se mantendrán",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "El valor 0 no establece un límite máximo. Después de que se descargue automáticamente un nuevo episodio, esto eliminará el episodio más antiguo si tiene más de X episodios. Esto solo eliminará 1 episodio por nueva descarga.",
|
||||||
"LabelMediaPlayer": "Reproductor de Medios",
|
"LabelMediaPlayer": "Reproductor de Medios",
|
||||||
"LabelMediaType": "Tipo de multimedia",
|
"LabelMediaType": "Tipo de multimedia",
|
||||||
"LabelMetaTag": "Metaetiqueta",
|
"LabelMetaTag": "Metaetiqueta",
|
||||||
@@ -458,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Nombre de la declaración OpenID que contiene una lista de grupos del usuario. Comúnmente conocidos como <code>grupos</code>. <b>Si se configura</b>, la aplicación asignará automáticamente roles en función de la pertenencia a grupos del usuario, siempre que estos grupos se denominen \"admin\", \"user\" o \"guest\" en la notificación. La solicitud debe contener una lista, y si un usuario pertenece a varios grupos, la aplicación asignará el rol correspondiente al mayor nivel de acceso. Si ningún grupo coincide, se denegará el acceso.",
|
"LabelOpenIDGroupClaimDescription": "Nombre de la declaración OpenID que contiene una lista de grupos del usuario. Comúnmente conocidos como <code>grupos</code>. <b>Si se configura</b>, la aplicación asignará automáticamente roles en función de la pertenencia a grupos del usuario, siempre que estos grupos se denominen \"admin\", \"user\" o \"guest\" en la notificación. La solicitud debe contener una lista, y si un usuario pertenece a varios grupos, la aplicación asignará el rol correspondiente al mayor nivel de acceso. Si ningún grupo coincide, se denegará el acceso.",
|
||||||
"LabelOpenRSSFeed": "Abrir Fuente RSS",
|
"LabelOpenRSSFeed": "Abrir Fuente RSS",
|
||||||
"LabelOverwrite": "Sobrescribir",
|
"LabelOverwrite": "Sobrescribir",
|
||||||
|
"LabelPaginationPageXOfY": "Página {0} de {1}",
|
||||||
"LabelPassword": "Contraseña",
|
"LabelPassword": "Contraseña",
|
||||||
"LabelPath": "Ruta de carpeta",
|
"LabelPath": "Ruta de carpeta",
|
||||||
"LabelPermanent": "Permanente",
|
"LabelPermanent": "Permanente",
|
||||||
"LabelPermissionsAccessAllLibraries": "Puede Accesar a Todas las bibliotecas",
|
"LabelPermissionsAccessAllLibraries": "Puede Accesar a Todas las bibliotecas",
|
||||||
"LabelPermissionsAccessAllTags": "Pueda Accesar a Todas las Etiquetas",
|
"LabelPermissionsAccessAllTags": "Pueda Accesar a Todas las Etiquetas",
|
||||||
"LabelPermissionsAccessExplicitContent": "Puede Accesar a Contenido Explicito",
|
"LabelPermissionsAccessExplicitContent": "Puede Accesar a Contenido Explicito",
|
||||||
|
"LabelPermissionsCreateEreader": "Puede crear un gestor de proyectos",
|
||||||
"LabelPermissionsDelete": "Puede Eliminar",
|
"LabelPermissionsDelete": "Puede Eliminar",
|
||||||
"LabelPermissionsDownload": "Puede Descargar",
|
"LabelPermissionsDownload": "Puede Descargar",
|
||||||
"LabelPermissionsUpdate": "Puede Actualizar",
|
"LabelPermissionsUpdate": "Puede Actualizar",
|
||||||
@@ -508,18 +517,24 @@
|
|||||||
"LabelRedo": "Rehacer",
|
"LabelRedo": "Rehacer",
|
||||||
"LabelRegion": "Región",
|
"LabelRegion": "Región",
|
||||||
"LabelReleaseDate": "Fecha de Estreno",
|
"LabelReleaseDate": "Fecha de Estreno",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Eliminar todos los archivos metadata.abs",
|
||||||
|
"LabelRemoveAllMetadataJson": "Eliminar todos los archivos metadata.json",
|
||||||
"LabelRemoveCover": "Remover Portada",
|
"LabelRemoveCover": "Remover Portada",
|
||||||
|
"LabelRemoveMetadataFile": "Eliminar archivos de metadatos en carpetas de elementos de biblioteca",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Elimine todos los archivos metadata.json y metadata.abs de sus carpetas {0}.",
|
||||||
"LabelRowsPerPage": "Filas por página",
|
"LabelRowsPerPage": "Filas por página",
|
||||||
"LabelSearchTerm": "Buscar Termino",
|
"LabelSearchTerm": "Buscar Termino",
|
||||||
"LabelSearchTitle": "Buscar Titulo",
|
"LabelSearchTitle": "Buscar Titulo",
|
||||||
"LabelSearchTitleOrASIN": "Buscar Título o ASIN",
|
"LabelSearchTitleOrASIN": "Buscar Título o ASIN",
|
||||||
"LabelSeason": "Temporada",
|
"LabelSeason": "Temporada",
|
||||||
|
"LabelSeasonNumber": "Sesión #{0}",
|
||||||
"LabelSelectAll": "Seleccionar todo",
|
"LabelSelectAll": "Seleccionar todo",
|
||||||
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
|
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
|
||||||
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
|
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
|
||||||
"LabelSelectUsers": "Seleccionar usuarios",
|
"LabelSelectUsers": "Seleccionar usuarios",
|
||||||
"LabelSendEbookToDevice": "Enviar Ebook a...",
|
"LabelSendEbookToDevice": "Enviar Ebook a...",
|
||||||
"LabelSequence": "Secuencia",
|
"LabelSequence": "Secuencia",
|
||||||
|
"LabelSerial": "Serial",
|
||||||
"LabelSeries": "Series",
|
"LabelSeries": "Series",
|
||||||
"LabelSeriesName": "Nombre de la Serie",
|
"LabelSeriesName": "Nombre de la Serie",
|
||||||
"LabelSeriesProgress": "Progreso de la Serie",
|
"LabelSeriesProgress": "Progreso de la Serie",
|
||||||
@@ -548,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Las series con un solo libro no aparecerán en la página de series ni la repisa para series de la página principal.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Las series con un solo libro no aparecerán en la página de series ni la repisa para series de la página principal.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Usar la vista de librero en la página principal",
|
"LabelSettingsHomePageBookshelfView": "Usar la vista de librero en la página principal",
|
||||||
"LabelSettingsLibraryBookshelfView": "Usar la vista de librero en la biblioteca",
|
"LabelSettingsLibraryBookshelfView": "Usar la vista de librero en la biblioteca",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "El porcentaje completado es mayor que",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "El tiempo restante es menor a (segundos)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Marcar el archivo multimedia como terminado cuando",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Saltar libros anteriores de la serie Continuada",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Saltar libros anteriores de la serie Continuada",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "El estante de la página de inicio de Continuar Serie muestra el primer libro no iniciado de una serie que tenga por lo menos un libro finalizado y no tenga libros en progreso. Habilitar esta opción le permitirá continuar series desde el último libro que ha completado en vez del primer libro que no ha empezado.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "El estante de la página de inicio de Continuar Serie muestra el primer libro no iniciado de una serie que tenga por lo menos un libro finalizado y no tenga libros en progreso. Habilitar esta opción le permitirá continuar series desde el último libro que ha completado en vez del primer libro que no ha empezado.",
|
||||||
"LabelSettingsParseSubtitles": "Extraer Subtítulos",
|
"LabelSettingsParseSubtitles": "Extraer Subtítulos",
|
||||||
@@ -612,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} minutos",
|
"LabelTimeDurationXMinutes": "{0} minutos",
|
||||||
"LabelTimeDurationXSeconds": "{0} segundos",
|
"LabelTimeDurationXSeconds": "{0} segundos",
|
||||||
"LabelTimeInMinutes": "Tiempo en minutos",
|
"LabelTimeInMinutes": "Tiempo en minutos",
|
||||||
|
"LabelTimeLeft": "Quedan {0}",
|
||||||
"LabelTimeListened": "Tiempo Escuchando",
|
"LabelTimeListened": "Tiempo Escuchando",
|
||||||
"LabelTimeListenedToday": "Tiempo Escuchando Hoy",
|
"LabelTimeListenedToday": "Tiempo Escuchando Hoy",
|
||||||
"LabelTimeRemaining": "{0} restante",
|
"LabelTimeRemaining": "{0} restante",
|
||||||
@@ -632,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "Varias pistas",
|
"LabelTracksMultiTrack": "Varias pistas",
|
||||||
"LabelTracksNone": "Ninguna pista",
|
"LabelTracksNone": "Ninguna pista",
|
||||||
"LabelTracksSingleTrack": "Una pista",
|
"LabelTracksSingleTrack": "Una pista",
|
||||||
|
"LabelTrailer": "Tráiler",
|
||||||
"LabelType": "Tipo",
|
"LabelType": "Tipo",
|
||||||
"LabelUnabridged": "No Abreviado",
|
"LabelUnabridged": "No Abreviado",
|
||||||
"LabelUndo": "Deshacer",
|
"LabelUndo": "Deshacer",
|
||||||
@@ -643,11 +663,13 @@
|
|||||||
"LabelUpdateDetailsHelp": "Permitir sobrescribir detalles existentes de los libros seleccionados cuando sean encontrados",
|
"LabelUpdateDetailsHelp": "Permitir sobrescribir detalles existentes de los libros seleccionados cuando sean encontrados",
|
||||||
"LabelUpdatedAt": "Actualizado En",
|
"LabelUpdatedAt": "Actualizado En",
|
||||||
"LabelUploaderDragAndDrop": "Arrastre y suelte archivos o carpetas",
|
"LabelUploaderDragAndDrop": "Arrastre y suelte archivos o carpetas",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Arrastrar y soltar archivos",
|
||||||
"LabelUploaderDropFiles": "Suelte los Archivos",
|
"LabelUploaderDropFiles": "Suelte los Archivos",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Buscar título, autor y series automáticamente",
|
"LabelUploaderItemFetchMetadataHelp": "Buscar título, autor y series automáticamente",
|
||||||
"LabelUseAdvancedOptions": "Usar opciones avanzadas",
|
"LabelUseAdvancedOptions": "Usar opciones avanzadas",
|
||||||
"LabelUseChapterTrack": "Usar pista por capitulo",
|
"LabelUseChapterTrack": "Usar pista por capitulo",
|
||||||
"LabelUseFullTrack": "Usar pista completa",
|
"LabelUseFullTrack": "Usar pista completa",
|
||||||
|
"LabelUseZeroForUnlimited": "Utilice 0 para ilimitado",
|
||||||
"LabelUser": "Usuario",
|
"LabelUser": "Usuario",
|
||||||
"LabelUsername": "Nombre de Usuario",
|
"LabelUsername": "Nombre de Usuario",
|
||||||
"LabelValue": "Valor",
|
"LabelValue": "Valor",
|
||||||
@@ -657,11 +679,13 @@
|
|||||||
"LabelViewPlayerSettings": "Ver los ajustes del reproductor",
|
"LabelViewPlayerSettings": "Ver los ajustes del reproductor",
|
||||||
"LabelViewQueue": "Ver Fila del Reproductor",
|
"LabelViewQueue": "Ver Fila del Reproductor",
|
||||||
"LabelVolume": "Volumen",
|
"LabelVolume": "Volumen",
|
||||||
|
"LabelWebRedirectURLsDescription": "Autorice estas URL en su proveedor OAuth para permitir la redirección a la aplicación web después de iniciar sesión:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Subcarpeta para URL de redireccionamiento",
|
||||||
"LabelWeekdaysToRun": "Correr en Días de la Semana",
|
"LabelWeekdaysToRun": "Correr en Días de la Semana",
|
||||||
"LabelXBooks": "{0} libros",
|
"LabelXBooks": "{0} libros",
|
||||||
"LabelXItems": "{0} elementos",
|
"LabelXItems": "{0} elementos",
|
||||||
"LabelYearReviewHide": "Ocultar Year in Review",
|
"LabelYearReviewHide": "Ocultar Resumen del año",
|
||||||
"LabelYearReviewShow": "Ver Year in Review",
|
"LabelYearReviewShow": "Resumen del año",
|
||||||
"LabelYourAudiobookDuration": "Duración de tu Audiolibro",
|
"LabelYourAudiobookDuration": "Duración de tu Audiolibro",
|
||||||
"LabelYourBookmarks": "Tus Marcadores",
|
"LabelYourBookmarks": "Tus Marcadores",
|
||||||
"LabelYourPlaylists": "Tus Listas",
|
"LabelYourPlaylists": "Tus Listas",
|
||||||
@@ -706,6 +730,7 @@
|
|||||||
"MessageConfirmPurgeCache": "Purgar el caché eliminará el directorio completo ubicado en <code>/metadata/cache</code>. <br /><br />¿Está seguro que desea eliminar el directorio del caché?",
|
"MessageConfirmPurgeCache": "Purgar el caché eliminará el directorio completo ubicado en <code>/metadata/cache</code>. <br /><br />¿Está seguro que desea eliminar el directorio del caché?",
|
||||||
"MessageConfirmPurgeItemsCache": "Purgar la caché de los elementos eliminará todo el directorio <code>/metadata/cache/items</code>.<br />¿Estás seguro?",
|
"MessageConfirmPurgeItemsCache": "Purgar la caché de los elementos eliminará todo el directorio <code>/metadata/cache/items</code>.<br />¿Estás seguro?",
|
||||||
"MessageConfirmQuickEmbed": "¡Advertencia! La integración rápida no realiza copias de seguridad a ninguno de tus archivos de audio. Asegúrate de haber realizado una copia de los mismos previamente. <br><br>¿Deseas continuar?",
|
"MessageConfirmQuickEmbed": "¡Advertencia! La integración rápida no realiza copias de seguridad a ninguno de tus archivos de audio. Asegúrate de haber realizado una copia de los mismos previamente. <br><br>¿Deseas continuar?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "El reconocimiento rápido de extensiones sobrescribirá los detalles si se encuentra una coincidencia. Se actualizarán las extensiones no reconocidas. ¿Está seguro?",
|
||||||
"MessageConfirmReScanLibraryItems": "¿Estás seguro de querer re escanear {0} elemento(s)?",
|
"MessageConfirmReScanLibraryItems": "¿Estás seguro de querer re escanear {0} elemento(s)?",
|
||||||
"MessageConfirmRemoveAllChapters": "¿Está seguro de que desea remover todos los capitulos?",
|
"MessageConfirmRemoveAllChapters": "¿Está seguro de que desea remover todos los capitulos?",
|
||||||
"MessageConfirmRemoveAuthor": "¿Está seguro de que desea remover el autor \"{0}\"?",
|
"MessageConfirmRemoveAuthor": "¿Está seguro de que desea remover el autor \"{0}\"?",
|
||||||
@@ -713,6 +738,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "¿Está seguro de que desea remover el episodio \"{0}\"?",
|
"MessageConfirmRemoveEpisode": "¿Está seguro de que desea remover el episodio \"{0}\"?",
|
||||||
"MessageConfirmRemoveEpisodes": "¿Está seguro de que desea remover {0} episodios?",
|
"MessageConfirmRemoveEpisodes": "¿Está seguro de que desea remover {0} episodios?",
|
||||||
"MessageConfirmRemoveListeningSessions": "¿Está seguro que desea remover {0} sesiones de escuchar?",
|
"MessageConfirmRemoveListeningSessions": "¿Está seguro que desea remover {0} sesiones de escuchar?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "¿Está seguro de que desea eliminar todos los archivos de metadatos.{0} en las carpetas de elementos de su biblioteca?",
|
||||||
"MessageConfirmRemoveNarrator": "¿Está seguro de que desea remover el narrador \"{0}\"?",
|
"MessageConfirmRemoveNarrator": "¿Está seguro de que desea remover el narrador \"{0}\"?",
|
||||||
"MessageConfirmRemovePlaylist": "¿Está seguro de que desea remover la lista de reproducción \"{0}\"?",
|
"MessageConfirmRemovePlaylist": "¿Está seguro de que desea remover la lista de reproducción \"{0}\"?",
|
||||||
"MessageConfirmRenameGenre": "¿Está seguro de que desea renombrar el genero \"{0}\" a \"{1}\" de todos los elementos?",
|
"MessageConfirmRenameGenre": "¿Está seguro de que desea renombrar el genero \"{0}\" a \"{1}\" de todos los elementos?",
|
||||||
@@ -756,7 +782,7 @@
|
|||||||
"MessageNoBackups": "Sin Respaldos",
|
"MessageNoBackups": "Sin Respaldos",
|
||||||
"MessageNoBookmarks": "Sin marcadores",
|
"MessageNoBookmarks": "Sin marcadores",
|
||||||
"MessageNoChapters": "Sin capítulos",
|
"MessageNoChapters": "Sin capítulos",
|
||||||
"MessageNoCollections": "Sin Colecciones",
|
"MessageNoCollections": "Sin colecciones",
|
||||||
"MessageNoCoversFound": "Ninguna Portada Encontrada",
|
"MessageNoCoversFound": "Ninguna Portada Encontrada",
|
||||||
"MessageNoDescription": "Sin Descripción",
|
"MessageNoDescription": "Sin Descripción",
|
||||||
"MessageNoDevices": "Sin dispositivos",
|
"MessageNoDevices": "Sin dispositivos",
|
||||||
@@ -793,6 +819,7 @@
|
|||||||
"MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS",
|
"MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS",
|
||||||
"MessageQuickEmbedInProgress": "Integración rápida en proceso",
|
"MessageQuickEmbedInProgress": "Integración rápida en proceso",
|
||||||
"MessageQuickEmbedQueue": "En cola para inserción rápida ({0} en cola)",
|
"MessageQuickEmbedQueue": "En cola para inserción rápida ({0} en cola)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Combina rápidamente todos los episodios",
|
||||||
"MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la opción \"Preferir Metadatos Encontrados\" del servidor esté habilitada.",
|
"MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la opción \"Preferir Metadatos Encontrados\" del servidor esté habilitada.",
|
||||||
"MessageRemoveChapter": "Remover capítulos",
|
"MessageRemoveChapter": "Remover capítulos",
|
||||||
"MessageRemoveEpisodes": "Remover {0} episodio(s)",
|
"MessageRemoveEpisodes": "Remover {0} episodio(s)",
|
||||||
@@ -891,6 +918,7 @@
|
|||||||
"StatsYearInReview": "RESEÑA DEL AÑO",
|
"StatsYearInReview": "RESEÑA DEL AÑO",
|
||||||
"ToastAccountUpdateSuccess": "Cuenta actualizada",
|
"ToastAccountUpdateSuccess": "Cuenta actualizada",
|
||||||
"ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise",
|
"ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise",
|
||||||
|
"ToastAsinRequired": "Se requiere ASIN",
|
||||||
"ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor",
|
"ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor",
|
||||||
"ToastAuthorNotFound": "No se encontró el autor \"{0}\"",
|
"ToastAuthorNotFound": "No se encontró el autor \"{0}\"",
|
||||||
"ToastAuthorRemoveSuccess": "Autor eliminado",
|
"ToastAuthorRemoveSuccess": "Autor eliminado",
|
||||||
@@ -910,6 +938,8 @@
|
|||||||
"ToastBackupUploadSuccess": "Respaldo cargado",
|
"ToastBackupUploadSuccess": "Respaldo cargado",
|
||||||
"ToastBatchDeleteFailed": "Error al eliminar por lotes",
|
"ToastBatchDeleteFailed": "Error al eliminar por lotes",
|
||||||
"ToastBatchDeleteSuccess": "Borrado por lotes correcto",
|
"ToastBatchDeleteSuccess": "Borrado por lotes correcto",
|
||||||
|
"ToastBatchQuickMatchFailed": "¡Error en la sincronización rápida por lotes!",
|
||||||
|
"ToastBatchQuickMatchStarted": "¡Se inició el lote de búsqueda rápida de {0} libros!",
|
||||||
"ToastBatchUpdateFailed": "Subida masiva fallida",
|
"ToastBatchUpdateFailed": "Subida masiva fallida",
|
||||||
"ToastBatchUpdateSuccess": "Subida masiva exitosa",
|
"ToastBatchUpdateSuccess": "Subida masiva exitosa",
|
||||||
"ToastBookmarkCreateFailed": "Error al crear marcador",
|
"ToastBookmarkCreateFailed": "Error al crear marcador",
|
||||||
@@ -921,6 +951,7 @@
|
|||||||
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
|
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
|
||||||
"ToastChaptersMustHaveTitles": "Los capítulos tienen que tener un título",
|
"ToastChaptersMustHaveTitles": "Los capítulos tienen que tener un título",
|
||||||
"ToastChaptersRemoved": "Capítulos eliminados",
|
"ToastChaptersRemoved": "Capítulos eliminados",
|
||||||
|
"ToastChaptersUpdated": "Capítulos actualizados",
|
||||||
"ToastCollectionItemsAddFailed": "Artículo(s) añadido(s) a la colección fallido(s)",
|
"ToastCollectionItemsAddFailed": "Artículo(s) añadido(s) a la colección fallido(s)",
|
||||||
"ToastCollectionItemsAddSuccess": "Artículo(s) añadido(s) a la colección correctamente",
|
"ToastCollectionItemsAddSuccess": "Artículo(s) añadido(s) a la colección correctamente",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección",
|
"ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección",
|
||||||
@@ -938,11 +969,14 @@
|
|||||||
"ToastEncodeCancelSucces": "Codificación cancelada",
|
"ToastEncodeCancelSucces": "Codificación cancelada",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "No se pudo borrar la cola",
|
"ToastEpisodeDownloadQueueClearFailed": "No se pudo borrar la cola",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "Se borró la cola de descargas de los episodios",
|
"ToastEpisodeDownloadQueueClearSuccess": "Se borró la cola de descargas de los episodios",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} episodio(s) actualizado(s)",
|
||||||
"ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo",
|
"ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo",
|
||||||
"ToastFailedToLoadData": "Error al cargar data",
|
"ToastFailedToLoadData": "Error al cargar data",
|
||||||
|
"ToastFailedToMatch": "Error al emparejar",
|
||||||
"ToastFailedToShare": "Error al compartir",
|
"ToastFailedToShare": "Error al compartir",
|
||||||
"ToastFailedToUpdate": "Error al actualizar",
|
"ToastFailedToUpdate": "Error al actualizar",
|
||||||
"ToastInvalidImageUrl": "URL de la imagen no válida",
|
"ToastInvalidImageUrl": "URL de la imagen no válida",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Número máximo de episodios para descargar no válidos",
|
||||||
"ToastInvalidUrl": "URL no válida",
|
"ToastInvalidUrl": "URL no válida",
|
||||||
"ToastItemCoverUpdateSuccess": "Portada del elemento actualizada",
|
"ToastItemCoverUpdateSuccess": "Portada del elemento actualizada",
|
||||||
"ToastItemDeletedFailed": "Error al eliminar el elemento",
|
"ToastItemDeletedFailed": "Error al eliminar el elemento",
|
||||||
@@ -961,14 +995,21 @@
|
|||||||
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
|
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
|
||||||
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
|
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
|
||||||
"ToastMatchAllAuthorsFailed": "No coincide con todos los autores",
|
"ToastMatchAllAuthorsFailed": "No coincide con todos los autores",
|
||||||
|
"ToastMetadataFilesRemovedError": "Error al eliminar metadatos de {0} archivo(s)",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "No hay metadatos.{0} archivo(s) encontrado(s) en la biblioteca",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Sin metadatos.{0} archivo(s) eliminado(s)",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadatos.{1} archivos eliminados",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Debe tener al menos una ruta",
|
||||||
"ToastNameEmailRequired": "Son obligatorios el nombre y el correo electrónico",
|
"ToastNameEmailRequired": "Son obligatorios el nombre y el correo electrónico",
|
||||||
"ToastNameRequired": "Nombre obligatorio",
|
"ToastNameRequired": "Nombre obligatorio",
|
||||||
|
"ToastNewEpisodesFound": "{0} nuevo(s) episodio(s) encontrado(s)",
|
||||||
"ToastNewUserCreatedFailed": "Error al crear la cuenta: \"{0}\"",
|
"ToastNewUserCreatedFailed": "Error al crear la cuenta: \"{0}\"",
|
||||||
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
|
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
|
||||||
"ToastNewUserLibraryError": "Debes seleccionar al menos una biblioteca",
|
"ToastNewUserLibraryError": "Debes seleccionar al menos una biblioteca",
|
||||||
"ToastNewUserPasswordError": "Debes tener una contraseña, solo el usuario root puede estar sin contraseña",
|
"ToastNewUserPasswordError": "Debes tener una contraseña, solo el usuario root puede estar sin contraseña",
|
||||||
"ToastNewUserTagError": "Debes seleccionar al menos una etiqueta",
|
"ToastNewUserTagError": "Debes seleccionar al menos una etiqueta",
|
||||||
"ToastNewUserUsernameError": "Introduce un nombre de usuario",
|
"ToastNewUserUsernameError": "Introduce un nombre de usuario",
|
||||||
|
"ToastNoNewEpisodesFound": "No se encontraron nuevos episodios",
|
||||||
"ToastNoUpdatesNecessary": "No es necesario actualizar",
|
"ToastNoUpdatesNecessary": "No es necesario actualizar",
|
||||||
"ToastNotificationCreateFailed": "Error al crear notificación",
|
"ToastNotificationCreateFailed": "Error al crear notificación",
|
||||||
"ToastNotificationDeleteFailed": "Error al borrar la notificación",
|
"ToastNotificationDeleteFailed": "Error al borrar la notificación",
|
||||||
@@ -987,6 +1028,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "No se puede obtener el podcast",
|
"ToastPodcastGetFeedFailed": "No se puede obtener el podcast",
|
||||||
"ToastPodcastNoEpisodesInFeed": "No se han encontrado episodios en el feed del RSS",
|
"ToastPodcastNoEpisodesInFeed": "No se han encontrado episodios en el feed del RSS",
|
||||||
"ToastPodcastNoRssFeed": "El podcast no tiene feed RSS",
|
"ToastPodcastNoRssFeed": "El podcast no tiene feed RSS",
|
||||||
|
"ToastProgressIsNotBeingSynced": "El progreso no se sincroniza, reinicia la reproducción",
|
||||||
"ToastProviderCreatedFailed": "Error al añadir el proveedor",
|
"ToastProviderCreatedFailed": "Error al añadir el proveedor",
|
||||||
"ToastProviderCreatedSuccess": "Nuevo proveedor añadido",
|
"ToastProviderCreatedSuccess": "Nuevo proveedor añadido",
|
||||||
"ToastProviderNameAndUrlRequired": "Nombre y Url obligatorios",
|
"ToastProviderNameAndUrlRequired": "Nombre y Url obligatorios",
|
||||||
@@ -1013,6 +1055,7 @@
|
|||||||
"ToastSessionCloseFailed": "Error al cerrar la sesión",
|
"ToastSessionCloseFailed": "Error al cerrar la sesión",
|
||||||
"ToastSessionDeleteFailed": "Error al eliminar sesión",
|
"ToastSessionDeleteFailed": "Error al eliminar sesión",
|
||||||
"ToastSessionDeleteSuccess": "Sesión eliminada",
|
"ToastSessionDeleteSuccess": "Sesión eliminada",
|
||||||
|
"ToastSleepTimerDone": "Temporizador de apagado automático activado... zZzzZz",
|
||||||
"ToastSlugMustChange": "El slug contiene caracteres no válidos",
|
"ToastSlugMustChange": "El slug contiene caracteres no válidos",
|
||||||
"ToastSlugRequired": "Slug obligatorio",
|
"ToastSlugRequired": "Slug obligatorio",
|
||||||
"ToastSocketConnected": "Socket conectado",
|
"ToastSocketConnected": "Socket conectado",
|
||||||
|
|||||||
+55
-6
@@ -122,7 +122,7 @@
|
|||||||
"HeaderBackups": "Sauvegardes",
|
"HeaderBackups": "Sauvegardes",
|
||||||
"HeaderChangePassword": "Modifier le mot de passe",
|
"HeaderChangePassword": "Modifier le mot de passe",
|
||||||
"HeaderChapters": "Chapitres",
|
"HeaderChapters": "Chapitres",
|
||||||
"HeaderChooseAFolder": "Choisir un dossier",
|
"HeaderChooseAFolder": "Sélectionner un dossier",
|
||||||
"HeaderCollection": "Collection",
|
"HeaderCollection": "Collection",
|
||||||
"HeaderCollectionItems": "Entrées de la collection",
|
"HeaderCollectionItems": "Entrées de la collection",
|
||||||
"HeaderCover": "Couverture",
|
"HeaderCover": "Couverture",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Mise à jour de la notification",
|
"HeaderNotificationUpdate": "Mise à jour de la notification",
|
||||||
"HeaderNotifications": "Notifications",
|
"HeaderNotifications": "Notifications",
|
||||||
"HeaderOpenIDConnectAuthentication": "Authentification via OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Authentification via OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Ouvrir les sessions d'écoutes",
|
||||||
"HeaderOpenRSSFeed": "Ouvrir le flux RSS",
|
"HeaderOpenRSSFeed": "Ouvrir le flux RSS",
|
||||||
"HeaderOtherFiles": "Autres fichiers",
|
"HeaderOtherFiles": "Autres fichiers",
|
||||||
"HeaderPasswordAuthentication": "Authentification par mot de passe",
|
"HeaderPasswordAuthentication": "Authentification par mot de passe",
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Suppression de {0} épisodes",
|
"HeaderRemoveEpisodes": "Suppression de {0} épisodes",
|
||||||
"HeaderSavedMediaProgress": "Progression de la sauvegarde des médias",
|
"HeaderSavedMediaProgress": "Progression de la sauvegarde des médias",
|
||||||
"HeaderSchedule": "Programmation",
|
"HeaderSchedule": "Programmation",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Programmer des téléchargements automatiques d'épisodes",
|
||||||
"HeaderScheduleLibraryScans": "Analyse automatique de la bibliothèque",
|
"HeaderScheduleLibraryScans": "Analyse automatique de la bibliothèque",
|
||||||
"HeaderSession": "Session",
|
"HeaderSession": "Session",
|
||||||
"HeaderSetBackupSchedule": "Activer la sauvegarde automatique",
|
"HeaderSetBackupSchedule": "Activer la sauvegarde automatique",
|
||||||
@@ -225,6 +227,7 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Tous les utilisateurs à l’exception des invités",
|
"LabelAllUsersExcludingGuests": "Tous les utilisateurs à l’exception des invités",
|
||||||
"LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités",
|
"LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités",
|
||||||
"LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque",
|
"LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque",
|
||||||
|
"LabelApiToken": "Token API",
|
||||||
"LabelAppend": "Ajouter",
|
"LabelAppend": "Ajouter",
|
||||||
"LabelAudioBitrate": "Débit audio (par exemple 128k)",
|
"LabelAudioBitrate": "Débit audio (par exemple 128k)",
|
||||||
"LabelAudioChannels": "Canaux audio (1 ou 2)",
|
"LabelAudioChannels": "Canaux audio (1 ou 2)",
|
||||||
@@ -250,15 +253,18 @@
|
|||||||
"LabelBackupsNumberToKeep": "Nombre de sauvegardes à conserver",
|
"LabelBackupsNumberToKeep": "Nombre de sauvegardes à conserver",
|
||||||
"LabelBackupsNumberToKeepHelp": "Seule une sauvegarde sera supprimée à la fois. Si vous avez déjà plus de sauvegardes à effacer, vous devez les supprimer manuellement.",
|
"LabelBackupsNumberToKeepHelp": "Seule une sauvegarde sera supprimée à la fois. Si vous avez déjà plus de sauvegardes à effacer, vous devez les supprimer manuellement.",
|
||||||
"LabelBitrate": "Débit binaire",
|
"LabelBitrate": "Débit binaire",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Livres",
|
"LabelBooks": "Livres",
|
||||||
"LabelButtonText": "Texte du bouton",
|
"LabelButtonText": "Texte du bouton",
|
||||||
"LabelByAuthor": "par {0}",
|
"LabelByAuthor": "par {0}",
|
||||||
"LabelChangePassword": "Modifier le mot de passe",
|
"LabelChangePassword": "Modifier le mot de passe",
|
||||||
"LabelChannels": "Canaux",
|
"LabelChannels": "Canaux",
|
||||||
|
"LabelChapterCount": "{0} Chapitres",
|
||||||
"LabelChapterTitle": "Titre du chapitre",
|
"LabelChapterTitle": "Titre du chapitre",
|
||||||
"LabelChapters": "Chapitres",
|
"LabelChapters": "Chapitres",
|
||||||
"LabelChaptersFound": "chapitres trouvés",
|
"LabelChaptersFound": "chapitres trouvés",
|
||||||
"LabelClickForMoreInfo": "Cliquez ici pour plus d’informations",
|
"LabelClickForMoreInfo": "Cliquez ici pour plus d’informations",
|
||||||
|
"LabelClickToUseCurrentValue": "Cliquez pour utiliser la valeur actuelle",
|
||||||
"LabelClosePlayer": "Fermer le lecteur",
|
"LabelClosePlayer": "Fermer le lecteur",
|
||||||
"LabelCodec": "Codec",
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Réduire les séries",
|
"LabelCollapseSeries": "Réduire les séries",
|
||||||
@@ -304,7 +310,7 @@
|
|||||||
"LabelEmailSettingsRejectUnauthorized": "Rejeter les certificats non autorisés",
|
"LabelEmailSettingsRejectUnauthorized": "Rejeter les certificats non autorisés",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Désactiver la validation du certificat SSL peut exposer votre connexion à des risques de sécurité, tels que des attaques de type « Attaque de l’homme du milieu ». Ne désactivez cette option que si vous en comprenez les implications et si vous faites confiance au serveur de messagerie auquel vous vous connectez.",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Désactiver la validation du certificat SSL peut exposer votre connexion à des risques de sécurité, tels que des attaques de type « Attaque de l’homme du milieu ». Ne désactivez cette option que si vous en comprenez les implications et si vous faites confiance au serveur de messagerie auquel vous vous connectez.",
|
||||||
"LabelEmailSettingsSecure": "Sécurisé",
|
"LabelEmailSettingsSecure": "Sécurisé",
|
||||||
"LabelEmailSettingsSecureHelp": "Si cette option est activée, la connexion utilisera TLS lors de la connexion au serveur. Si elle est désactivée, TLS sera utilisé uniquement si le serveur prend en charge l’extension STARTTLS. Dans la plupart des cas, définissez cette valeur sur « true » si vous vous connectez au port 465. Pour les ports 587 ou 25, laissez-la sur « false ». (source : nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Si cette option est activée, la connexion utilisera TLS lors de la connexion au serveur. Si elle est désactivée, TLS sera utilisé uniquement si le serveur prend en charge l’extension STARTTLS. Dans la plupart des cas, définissez cette valeur sur « true » si vous vous connectez au port 465. Pour les ports 587 ou 25, laissez-la sur « false ». (source : nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "Adresse de test",
|
"LabelEmailSettingsTestAddress": "Adresse de test",
|
||||||
"LabelEmbeddedCover": "Couverture du livre intégrée",
|
"LabelEmbeddedCover": "Couverture du livre intégrée",
|
||||||
"LabelEnable": "Activer",
|
"LabelEnable": "Activer",
|
||||||
@@ -320,9 +326,13 @@
|
|||||||
"LabelEnd": "Fin",
|
"LabelEnd": "Fin",
|
||||||
"LabelEndOfChapter": "Fin du chapitre",
|
"LabelEndOfChapter": "Fin du chapitre",
|
||||||
"LabelEpisode": "Épisode",
|
"LabelEpisode": "Épisode",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Épisode non lié au flux RSS",
|
||||||
|
"LabelEpisodeNumber": "Épisode n°{0}",
|
||||||
"LabelEpisodeTitle": "Titre de l’épisode",
|
"LabelEpisodeTitle": "Titre de l’épisode",
|
||||||
"LabelEpisodeType": "Type de l’épisode",
|
"LabelEpisodeType": "Type de l’épisode",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "URL de l’épisode à partir du flux RSS",
|
||||||
"LabelEpisodes": "Épisodes",
|
"LabelEpisodes": "Épisodes",
|
||||||
|
"LabelEpisodic": "Épisodique",
|
||||||
"LabelExample": "Exemple",
|
"LabelExample": "Exemple",
|
||||||
"LabelExpandSeries": "Développer la série",
|
"LabelExpandSeries": "Développer la série",
|
||||||
"LabelExpandSubSeries": "Développer les sous-séries",
|
"LabelExpandSubSeries": "Développer les sous-séries",
|
||||||
@@ -350,6 +360,7 @@
|
|||||||
"LabelFontScale": "Taille de la police de caractère",
|
"LabelFontScale": "Taille de la police de caractère",
|
||||||
"LabelFontStrikethrough": "Barrer",
|
"LabelFontStrikethrough": "Barrer",
|
||||||
"LabelFormat": "Format",
|
"LabelFormat": "Format",
|
||||||
|
"LabelFull": "Complet",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Suppression du fichier",
|
"LabelHardDeleteFile": "Suppression du fichier",
|
||||||
@@ -405,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "Priorité la plus basse",
|
"LabelLowestPriority": "Priorité la plus basse",
|
||||||
"LabelMatchExistingUsersBy": "Correspondance avec les utilisateurs existants",
|
"LabelMatchExistingUsersBy": "Correspondance avec les utilisateurs existants",
|
||||||
"LabelMatchExistingUsersByDescription": "Utilisé pour connecter les utilisateurs existants. Une fois connectés, les utilisateurs seront associés à un identifiant unique provenant de votre fournisseur SSO",
|
"LabelMatchExistingUsersByDescription": "Utilisé pour connecter les utilisateurs existants. Une fois connectés, les utilisateurs seront associés à un identifiant unique provenant de votre fournisseur SSO",
|
||||||
|
"LabelMaxEpisodesToDownload": "Nombre maximum d’épisodes à télécharger. 0 pour illimité.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Nombre maximum de nouveaux épisodes à télécharger par vérification",
|
||||||
|
"LabelMaxEpisodesToKeep": "Nombre maximum d’épisodes à conserver",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "La valeur 0 ne définit aucune limite maximale. Une fois qu’un nouvel épisode est téléchargé automatiquement, l’épisode le plus ancien sera supprimé si vous avez plus de X épisodes. Cela ne supprimera qu’un seul épisode par nouveau téléchargement.",
|
||||||
"LabelMediaPlayer": "Lecteur multimédia",
|
"LabelMediaPlayer": "Lecteur multimédia",
|
||||||
"LabelMediaType": "Type de média",
|
"LabelMediaType": "Type de média",
|
||||||
"LabelMetaTag": "Balise de métadonnée",
|
"LabelMetaTag": "Balise de métadonnée",
|
||||||
@@ -450,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Nom de la demande OpenID qui contient une liste des groupes de l’utilisateur. Communément appelé <code>groups</code>. <b>Si elle est configurée</b>, l’application attribuera automatiquement des rôles en fonction de l’appartenance de l’utilisateur à un groupe, à condition que ces groupes soient nommés -sensible à la casse- tel que « admin », « user » ou « guest » dans la demande. Elle doit contenir une liste, et si un utilisateur appartient à plusieurs groupes, l’application attribuera le rôle correspondant au niveau d’accès le plus élevé. Si aucun groupe ne correspond, l’accès sera refusé.",
|
"LabelOpenIDGroupClaimDescription": "Nom de la demande OpenID qui contient une liste des groupes de l’utilisateur. Communément appelé <code>groups</code>. <b>Si elle est configurée</b>, l’application attribuera automatiquement des rôles en fonction de l’appartenance de l’utilisateur à un groupe, à condition que ces groupes soient nommés -sensible à la casse- tel que « admin », « user » ou « guest » dans la demande. Elle doit contenir une liste, et si un utilisateur appartient à plusieurs groupes, l’application attribuera le rôle correspondant au niveau d’accès le plus élevé. Si aucun groupe ne correspond, l’accès sera refusé.",
|
||||||
"LabelOpenRSSFeed": "Ouvrir le flux RSS",
|
"LabelOpenRSSFeed": "Ouvrir le flux RSS",
|
||||||
"LabelOverwrite": "Écraser",
|
"LabelOverwrite": "Écraser",
|
||||||
|
"LabelPaginationPageXOfY": "Page {0} sur {1}",
|
||||||
"LabelPassword": "Mot de passe",
|
"LabelPassword": "Mot de passe",
|
||||||
"LabelPath": "Chemin",
|
"LabelPath": "Chemin",
|
||||||
"LabelPermanent": "Permanent",
|
"LabelPermanent": "Permanent",
|
||||||
"LabelPermissionsAccessAllLibraries": "Peut accéder à toutes les bibliothèque",
|
"LabelPermissionsAccessAllLibraries": "Peut accéder à toutes les bibliothèque",
|
||||||
"LabelPermissionsAccessAllTags": "Peut accéder à toutes les étiquettes",
|
"LabelPermissionsAccessAllTags": "Peut accéder à toutes les étiquettes",
|
||||||
"LabelPermissionsAccessExplicitContent": "Peut accéder au contenu restreint",
|
"LabelPermissionsAccessExplicitContent": "Peut accéder au contenu restreint",
|
||||||
|
"LabelPermissionsCreateEreader": "Peut créer une liseuse",
|
||||||
"LabelPermissionsDelete": "Peut supprimer",
|
"LabelPermissionsDelete": "Peut supprimer",
|
||||||
"LabelPermissionsDownload": "Peut télécharger",
|
"LabelPermissionsDownload": "Peut télécharger",
|
||||||
"LabelPermissionsUpdate": "Peut mettre à jour",
|
"LabelPermissionsUpdate": "Peut mettre à jour",
|
||||||
@@ -500,18 +517,24 @@
|
|||||||
"LabelRedo": "Refaire",
|
"LabelRedo": "Refaire",
|
||||||
"LabelRegion": "Région",
|
"LabelRegion": "Région",
|
||||||
"LabelReleaseDate": "Date de parution",
|
"LabelReleaseDate": "Date de parution",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Supprimer tous les fichiers metadata.abs",
|
||||||
|
"LabelRemoveAllMetadataJson": "Supprimer tous les fichiers metadata.json",
|
||||||
"LabelRemoveCover": "Supprimer la couverture",
|
"LabelRemoveCover": "Supprimer la couverture",
|
||||||
|
"LabelRemoveMetadataFile": "Supprimer les fichiers de métadonnées dans les dossiers des éléments de la bibliothèque",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Supprimer tous les fichiers metadata.json et metadata.abs de vos dossiers {0}.",
|
||||||
"LabelRowsPerPage": "Lignes par page",
|
"LabelRowsPerPage": "Lignes par page",
|
||||||
"LabelSearchTerm": "Terme de recherche",
|
"LabelSearchTerm": "Terme de recherche",
|
||||||
"LabelSearchTitle": "Titre de recherche",
|
"LabelSearchTitle": "Titre de recherche",
|
||||||
"LabelSearchTitleOrASIN": "Recherche du titre ou ASIN",
|
"LabelSearchTitleOrASIN": "Recherche du titre ou ASIN",
|
||||||
"LabelSeason": "Saison",
|
"LabelSeason": "Saison",
|
||||||
|
"LabelSeasonNumber": "Saison n°{0}",
|
||||||
"LabelSelectAll": "Tout sélectionner",
|
"LabelSelectAll": "Tout sélectionner",
|
||||||
"LabelSelectAllEpisodes": "Sélectionner tous les épisodes",
|
"LabelSelectAllEpisodes": "Sélectionner tous les épisodes",
|
||||||
"LabelSelectEpisodesShowing": "Sélectionner {0} épisode(s) en cours",
|
"LabelSelectEpisodesShowing": "Sélectionner {0} épisode(s) en cours",
|
||||||
"LabelSelectUsers": "Sélectionner les utilisateurs",
|
"LabelSelectUsers": "Sélectionner les utilisateurs",
|
||||||
"LabelSendEbookToDevice": "Envoyer le livre numérique à…",
|
"LabelSendEbookToDevice": "Envoyer le livre numérique à…",
|
||||||
"LabelSequence": "Séquence",
|
"LabelSequence": "Séquence",
|
||||||
|
"LabelSerial": "N° de série",
|
||||||
"LabelSeries": "Séries",
|
"LabelSeries": "Séries",
|
||||||
"LabelSeriesName": "Nom de la série",
|
"LabelSeriesName": "Nom de la série",
|
||||||
"LabelSeriesProgress": "Progression de séries",
|
"LabelSeriesProgress": "Progression de séries",
|
||||||
@@ -540,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Les séries qui ne comportent qu’un seul livre seront masquées sur la page de la série et sur les étagères de la page d’accueil.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Les séries qui ne comportent qu’un seul livre seront masquées sur la page de la série et sur les étagères de la page d’accueil.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Utiliser la vue étagère sur la page d’accueil",
|
"LabelSettingsHomePageBookshelfView": "Utiliser la vue étagère sur la page d’accueil",
|
||||||
"LabelSettingsLibraryBookshelfView": "Utiliser la vue étagère pour la bibliothèque",
|
"LabelSettingsLibraryBookshelfView": "Utiliser la vue étagère pour la bibliothèque",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Le pourcentage d'achèvement est supérieur à",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Le temps restant est inférieur à (secondes)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Marquer l’élément multimédia comme terminé lorsque",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Sauter les livres précédents dans « Continuer la série »",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Sauter les livres précédents dans « Continuer la série »",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "L’étagère de la page d’accueil « Continuer la série » affiche le premier livre non commencé dans les séries dont au moins un livre est terminé et aucun livre n’est en cours. L’activation de ce paramètre permet de poursuivre la série à partir du dernier livre terminé au lieu du premier livre non commencé.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "L’étagère de la page d’accueil « Continuer la série » affiche le premier livre non commencé dans les séries dont au moins un livre est terminé et aucun livre n’est en cours. L’activation de ce paramètre permet de poursuivre la série à partir du dernier livre terminé au lieu du premier livre non commencé.",
|
||||||
"LabelSettingsParseSubtitles": "Analyser les sous-titres",
|
"LabelSettingsParseSubtitles": "Analyser les sous-titres",
|
||||||
@@ -604,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} minutes",
|
"LabelTimeDurationXMinutes": "{0} minutes",
|
||||||
"LabelTimeDurationXSeconds": "{0} secondes",
|
"LabelTimeDurationXSeconds": "{0} secondes",
|
||||||
"LabelTimeInMinutes": "Temps en minutes",
|
"LabelTimeInMinutes": "Temps en minutes",
|
||||||
|
"LabelTimeLeft": "{0} restant",
|
||||||
"LabelTimeListened": "Temps d’écoute",
|
"LabelTimeListened": "Temps d’écoute",
|
||||||
"LabelTimeListenedToday": "Nombres d’écoutes aujourd’hui",
|
"LabelTimeListenedToday": "Nombres d’écoutes aujourd’hui",
|
||||||
"LabelTimeRemaining": "{0} restantes",
|
"LabelTimeRemaining": "{0} restantes",
|
||||||
@@ -624,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "Piste multiple",
|
"LabelTracksMultiTrack": "Piste multiple",
|
||||||
"LabelTracksNone": "Aucune piste",
|
"LabelTracksNone": "Aucune piste",
|
||||||
"LabelTracksSingleTrack": "Piste simple",
|
"LabelTracksSingleTrack": "Piste simple",
|
||||||
|
"LabelTrailer": "Bande-annonce",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Version intégrale",
|
"LabelUnabridged": "Version intégrale",
|
||||||
"LabelUndo": "Annuler",
|
"LabelUndo": "Annuler",
|
||||||
@@ -635,11 +663,13 @@
|
|||||||
"LabelUpdateDetailsHelp": "Autoriser la mise à jour des détails existants lorsqu’une correspondance est trouvée",
|
"LabelUpdateDetailsHelp": "Autoriser la mise à jour des détails existants lorsqu’une correspondance est trouvée",
|
||||||
"LabelUpdatedAt": "Mis à jour à",
|
"LabelUpdatedAt": "Mis à jour à",
|
||||||
"LabelUploaderDragAndDrop": "Glisser et déposer des fichiers ou dossiers",
|
"LabelUploaderDragAndDrop": "Glisser et déposer des fichiers ou dossiers",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Glisser & déposer des fichiers",
|
||||||
"LabelUploaderDropFiles": "Déposer des fichiers",
|
"LabelUploaderDropFiles": "Déposer des fichiers",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Récupérer automatiquement le titre, l’auteur et la série",
|
"LabelUploaderItemFetchMetadataHelp": "Récupérer automatiquement le titre, l’auteur et la série",
|
||||||
"LabelUseAdvancedOptions": "Utiliser les options avancées",
|
"LabelUseAdvancedOptions": "Utiliser les options avancées",
|
||||||
"LabelUseChapterTrack": "Utiliser la piste du chapitre",
|
"LabelUseChapterTrack": "Utiliser la piste du chapitre",
|
||||||
"LabelUseFullTrack": "Utiliser la piste complète",
|
"LabelUseFullTrack": "Utiliser la piste complète",
|
||||||
|
"LabelUseZeroForUnlimited": "0 pour illimité",
|
||||||
"LabelUser": "Utilisateur",
|
"LabelUser": "Utilisateur",
|
||||||
"LabelUsername": "Nom d’utilisateur",
|
"LabelUsername": "Nom d’utilisateur",
|
||||||
"LabelValue": "Valeur",
|
"LabelValue": "Valeur",
|
||||||
@@ -686,7 +716,7 @@
|
|||||||
"MessageConfirmDeleteMetadataProvider": "Êtes-vous sûr·e de vouloir supprimer le fournisseur de métadonnées personnalisées « {0} » ?",
|
"MessageConfirmDeleteMetadataProvider": "Êtes-vous sûr·e de vouloir supprimer le fournisseur de métadonnées personnalisées « {0} » ?",
|
||||||
"MessageConfirmDeleteNotification": "Êtes-vous sûr·e de vouloir supprimer cette notification ?",
|
"MessageConfirmDeleteNotification": "Êtes-vous sûr·e de vouloir supprimer cette notification ?",
|
||||||
"MessageConfirmDeleteSession": "Êtes-vous sûr·e de vouloir supprimer cette session ?",
|
"MessageConfirmDeleteSession": "Êtes-vous sûr·e de vouloir supprimer cette session ?",
|
||||||
"MessageConfirmEmbedMetadataInAudioFiles": "Souhaitez-vous vraiment intégrer des métadonnées dans {0} fichiers audio ?",
|
"MessageConfirmEmbedMetadataInAudioFiles": "Êtes-vous sûr·e de vouloir intégrer des métadonnées dans {0} fichiers audio ?",
|
||||||
"MessageConfirmForceReScan": "Êtes-vous sûr·e de vouloir lancer une analyse forcée ?",
|
"MessageConfirmForceReScan": "Êtes-vous sûr·e de vouloir lancer une analyse forcée ?",
|
||||||
"MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr·e de marquer tous les épisodes comme terminés ?",
|
"MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr·e de marquer tous les épisodes comme terminés ?",
|
||||||
"MessageConfirmMarkAllEpisodesNotFinished": "Êtes-vous sûr·e de vouloir marquer tous les épisodes comme non terminés ?",
|
"MessageConfirmMarkAllEpisodesNotFinished": "Êtes-vous sûr·e de vouloir marquer tous les épisodes comme non terminés ?",
|
||||||
@@ -697,7 +727,8 @@
|
|||||||
"MessageConfirmNotificationTestTrigger": "Déclencher cette notification avec des données de test ?",
|
"MessageConfirmNotificationTestTrigger": "Déclencher cette notification avec des données de test ?",
|
||||||
"MessageConfirmPurgeCache": "La purge du cache supprimera l’intégralité du répertoire à <code>/metadata/cache</code>.<br /><br />Êtes-vous sûr·e de vouloir supprimer le répertoire de cache ?",
|
"MessageConfirmPurgeCache": "La purge du cache supprimera l’intégralité du répertoire à <code>/metadata/cache</code>.<br /><br />Êtes-vous sûr·e de vouloir supprimer le répertoire de cache ?",
|
||||||
"MessageConfirmPurgeItemsCache": "Purger le cache des éléments supprimera l'ensemble du répertoire <code>/metadata/cache/items</code>.<br />Êtes-vous sûr ?",
|
"MessageConfirmPurgeItemsCache": "Purger le cache des éléments supprimera l'ensemble du répertoire <code>/metadata/cache/items</code>.<br />Êtes-vous sûr ?",
|
||||||
"MessageConfirmQuickEmbed": "Attention ! L'intégration rapide ne permet pas de sauvegarder vos fichiers audio. Assurez-vous d’avoir effectuer une sauvegarde de vos fichiers audio.<br><br>Souhaitez-vous continuer ?",
|
"MessageConfirmQuickEmbed": "Attention ! L'intégration rapide ne permet pas de sauvegarder vos fichiers audio. Assurez-vous d’avoir effectuer une sauvegarde de vos fichiers audio.<br><br>Êtes-vous sûr·e de vouloir continuer ?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "Les épisodes correspondants seront écrasés si une correspondance est trouvée. Seuls les épisodes non correspondants seront mis à jour. Êtes-vous sûr·e ?",
|
||||||
"MessageConfirmReScanLibraryItems": "Êtes-vous sûr·e de vouloir réanalyser {0} éléments ?",
|
"MessageConfirmReScanLibraryItems": "Êtes-vous sûr·e de vouloir réanalyser {0} éléments ?",
|
||||||
"MessageConfirmRemoveAllChapters": "Êtes-vous sûr·e de vouloir supprimer tous les chapitres ?",
|
"MessageConfirmRemoveAllChapters": "Êtes-vous sûr·e de vouloir supprimer tous les chapitres ?",
|
||||||
"MessageConfirmRemoveAuthor": "Êtes-vous sûr·e de vouloir supprimer l’auteur « {0} » ?",
|
"MessageConfirmRemoveAuthor": "Êtes-vous sûr·e de vouloir supprimer l’auteur « {0} » ?",
|
||||||
@@ -705,6 +736,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "Êtes-vous sûr·e de vouloir supprimer l’épisode « {0} » ?",
|
"MessageConfirmRemoveEpisode": "Êtes-vous sûr·e de vouloir supprimer l’épisode « {0} » ?",
|
||||||
"MessageConfirmRemoveEpisodes": "Êtes-vous sûr·e de vouloir supprimer {0} épisodes ?",
|
"MessageConfirmRemoveEpisodes": "Êtes-vous sûr·e de vouloir supprimer {0} épisodes ?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Êtes-vous sûr·e de vouloir supprimer {0} sessions d’écoute ?",
|
"MessageConfirmRemoveListeningSessions": "Êtes-vous sûr·e de vouloir supprimer {0} sessions d’écoute ?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Êtes-vous sûr·e de vouloir supprimer tous les fichiers « metatadata.{0} » des dossiers d’éléments de votre bibliothèque ?",
|
||||||
"MessageConfirmRemoveNarrator": "Êtes-vous sûr·e de vouloir supprimer le narrateur « {0} » ?",
|
"MessageConfirmRemoveNarrator": "Êtes-vous sûr·e de vouloir supprimer le narrateur « {0} » ?",
|
||||||
"MessageConfirmRemovePlaylist": "Êtes-vous sûr·e de vouloir supprimer la liste de lecture « {0} » ?",
|
"MessageConfirmRemovePlaylist": "Êtes-vous sûr·e de vouloir supprimer la liste de lecture « {0} » ?",
|
||||||
"MessageConfirmRenameGenre": "Êtes-vous sûr·e de vouloir renommer le genre « {0} » en « {1} » pour tous les éléments ?",
|
"MessageConfirmRenameGenre": "Êtes-vous sûr·e de vouloir renommer le genre « {0} » en « {1} » pour tous les éléments ?",
|
||||||
@@ -785,6 +817,7 @@
|
|||||||
"MessagePodcastSearchField": "Saisissez le terme de recherche ou l'URL du flux RSS",
|
"MessagePodcastSearchField": "Saisissez le terme de recherche ou l'URL du flux RSS",
|
||||||
"MessageQuickEmbedInProgress": "Intégration rapide en cours",
|
"MessageQuickEmbedInProgress": "Intégration rapide en cours",
|
||||||
"MessageQuickEmbedQueue": "En file d'attente pour une intégration rapide ({0} dans la file d'attente)",
|
"MessageQuickEmbedQueue": "En file d'attente pour une intégration rapide ({0} dans la file d'attente)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Associer rapidement tous les épisodes",
|
||||||
"MessageQuickMatchDescription": "Renseigne les détails manquants ainsi que la couverture avec la première correspondance de « {0} ». N’écrase pas les données présentes à moins que le paramètre « Préférer les Métadonnées par correspondance » soit activé.",
|
"MessageQuickMatchDescription": "Renseigne les détails manquants ainsi que la couverture avec la première correspondance de « {0} ». N’écrase pas les données présentes à moins que le paramètre « Préférer les Métadonnées par correspondance » soit activé.",
|
||||||
"MessageRemoveChapter": "Supprimer le chapitre",
|
"MessageRemoveChapter": "Supprimer le chapitre",
|
||||||
"MessageRemoveEpisodes": "Suppression de {0} épisode(s)",
|
"MessageRemoveEpisodes": "Suppression de {0} épisode(s)",
|
||||||
@@ -837,10 +870,10 @@
|
|||||||
"MessageTaskScanningFileChanges": "Analyse des modifications du fichier dans « {0} »",
|
"MessageTaskScanningFileChanges": "Analyse des modifications du fichier dans « {0} »",
|
||||||
"MessageTaskScanningLibrary": "Analyse de la bibliothèque « {0} »",
|
"MessageTaskScanningLibrary": "Analyse de la bibliothèque « {0} »",
|
||||||
"MessageTaskTargetDirectoryNotWritable": "Le répertoire cible n’est pas accessible en écriture",
|
"MessageTaskTargetDirectoryNotWritable": "Le répertoire cible n’est pas accessible en écriture",
|
||||||
"MessageThinking": "Je cherche…",
|
"MessageThinking": "À la recherche de…",
|
||||||
"MessageUploaderItemFailed": "Échec du téléversement",
|
"MessageUploaderItemFailed": "Échec du téléversement",
|
||||||
"MessageUploaderItemSuccess": "Téléversement effectué !",
|
"MessageUploaderItemSuccess": "Téléversement effectué !",
|
||||||
"MessageUploading": "Téléversement…",
|
"MessageUploading": "Téléchargement…",
|
||||||
"MessageValidCronExpression": "Expression cron valide",
|
"MessageValidCronExpression": "Expression cron valide",
|
||||||
"MessageWatcherIsDisabledGlobally": "La surveillance est désactivée par un paramètre global du serveur",
|
"MessageWatcherIsDisabledGlobally": "La surveillance est désactivée par un paramètre global du serveur",
|
||||||
"MessageXLibraryIsEmpty": "La bibliothèque {0} est vide !",
|
"MessageXLibraryIsEmpty": "La bibliothèque {0} est vide !",
|
||||||
@@ -883,6 +916,7 @@
|
|||||||
"StatsYearInReview": "BILAN DE L’ANNÉE",
|
"StatsYearInReview": "BILAN DE L’ANNÉE",
|
||||||
"ToastAccountUpdateSuccess": "Compte mis à jour",
|
"ToastAccountUpdateSuccess": "Compte mis à jour",
|
||||||
"ToastAppriseUrlRequired": "Vous devez entrer une URL Apprise",
|
"ToastAppriseUrlRequired": "Vous devez entrer une URL Apprise",
|
||||||
|
"ToastAsinRequired": "ASIN requis",
|
||||||
"ToastAuthorImageRemoveSuccess": "Image de l’auteur supprimée",
|
"ToastAuthorImageRemoveSuccess": "Image de l’auteur supprimée",
|
||||||
"ToastAuthorNotFound": "Auteur \"{0}\" non trouvé",
|
"ToastAuthorNotFound": "Auteur \"{0}\" non trouvé",
|
||||||
"ToastAuthorRemoveSuccess": "Auteur supprimé",
|
"ToastAuthorRemoveSuccess": "Auteur supprimé",
|
||||||
@@ -902,6 +936,8 @@
|
|||||||
"ToastBackupUploadSuccess": "Sauvegarde téléversée",
|
"ToastBackupUploadSuccess": "Sauvegarde téléversée",
|
||||||
"ToastBatchDeleteFailed": "Échec de la suppression par lot",
|
"ToastBatchDeleteFailed": "Échec de la suppression par lot",
|
||||||
"ToastBatchDeleteSuccess": "Suppression par lot réussie",
|
"ToastBatchDeleteSuccess": "Suppression par lot réussie",
|
||||||
|
"ToastBatchQuickMatchFailed": "Échec de la correspondance rapide par lot !",
|
||||||
|
"ToastBatchQuickMatchStarted": "La correspondance rapide par lots de {0} livres a commencé !",
|
||||||
"ToastBatchUpdateFailed": "Échec de la mise à jour par lot",
|
"ToastBatchUpdateFailed": "Échec de la mise à jour par lot",
|
||||||
"ToastBatchUpdateSuccess": "Mise à jour par lot terminée",
|
"ToastBatchUpdateSuccess": "Mise à jour par lot terminée",
|
||||||
"ToastBookmarkCreateFailed": "Échec de la création de signet",
|
"ToastBookmarkCreateFailed": "Échec de la création de signet",
|
||||||
@@ -913,6 +949,7 @@
|
|||||||
"ToastChaptersHaveErrors": "Les chapitres contiennent des erreurs",
|
"ToastChaptersHaveErrors": "Les chapitres contiennent des erreurs",
|
||||||
"ToastChaptersMustHaveTitles": "Les chapitre doivent avoir un titre",
|
"ToastChaptersMustHaveTitles": "Les chapitre doivent avoir un titre",
|
||||||
"ToastChaptersRemoved": "Chapitres supprimés",
|
"ToastChaptersRemoved": "Chapitres supprimés",
|
||||||
|
"ToastChaptersUpdated": "Chapitres mis à jour",
|
||||||
"ToastCollectionItemsAddFailed": "Échec de l’ajout de(s) élément(s) à la collection",
|
"ToastCollectionItemsAddFailed": "Échec de l’ajout de(s) élément(s) à la collection",
|
||||||
"ToastCollectionItemsAddSuccess": "Ajout de(s) élément(s) à la collection réussi",
|
"ToastCollectionItemsAddSuccess": "Ajout de(s) élément(s) à la collection réussi",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Élément(s) supprimé(s) de la collection",
|
"ToastCollectionItemsRemoveSuccess": "Élément(s) supprimé(s) de la collection",
|
||||||
@@ -930,11 +967,14 @@
|
|||||||
"ToastEncodeCancelSucces": "Encodage annulé",
|
"ToastEncodeCancelSucces": "Encodage annulé",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "Échec de la suppression de la file d'attente",
|
"ToastEpisodeDownloadQueueClearFailed": "Échec de la suppression de la file d'attente",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "File d’attente de téléchargement des épisodes effacée",
|
"ToastEpisodeDownloadQueueClearSuccess": "File d’attente de téléchargement des épisodes effacée",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} épisodes mis à jour",
|
||||||
"ToastErrorCannotShare": "Impossible de partager nativement sur cet appareil",
|
"ToastErrorCannotShare": "Impossible de partager nativement sur cet appareil",
|
||||||
"ToastFailedToLoadData": "Échec du chargement des données",
|
"ToastFailedToLoadData": "Échec du chargement des données",
|
||||||
|
"ToastFailedToMatch": "Échec de la correspondance",
|
||||||
"ToastFailedToShare": "Échec du partage",
|
"ToastFailedToShare": "Échec du partage",
|
||||||
"ToastFailedToUpdate": "Échec de la mise à jour",
|
"ToastFailedToUpdate": "Échec de la mise à jour",
|
||||||
"ToastInvalidImageUrl": "URL de l'image invalide",
|
"ToastInvalidImageUrl": "URL de l'image invalide",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Nombre maximum d’épisodes à télécharger non valide",
|
||||||
"ToastInvalidUrl": "URL invalide",
|
"ToastInvalidUrl": "URL invalide",
|
||||||
"ToastItemCoverUpdateSuccess": "Couverture mise à jour",
|
"ToastItemCoverUpdateSuccess": "Couverture mise à jour",
|
||||||
"ToastItemDeletedFailed": "La suppression de l'élément à échouée",
|
"ToastItemDeletedFailed": "La suppression de l'élément à échouée",
|
||||||
@@ -953,14 +993,21 @@
|
|||||||
"ToastLibraryScanStarted": "Analyse de la bibliothèque démarrée",
|
"ToastLibraryScanStarted": "Analyse de la bibliothèque démarrée",
|
||||||
"ToastLibraryUpdateSuccess": "Bibliothèque « {0} » mise à jour",
|
"ToastLibraryUpdateSuccess": "Bibliothèque « {0} » mise à jour",
|
||||||
"ToastMatchAllAuthorsFailed": "Tous les auteurs et autrices n’ont pas pu être classés",
|
"ToastMatchAllAuthorsFailed": "Tous les auteurs et autrices n’ont pas pu être classés",
|
||||||
|
"ToastMetadataFilesRemovedError": "Erreur lors de la suppression des fichiers « metadata.{0} »",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "Aucun fichier « metadata.{0} » trouvé dans la bibliothèque",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Aucun fichier « metadata.{0} » n’a été supprimé",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} fichiers metadata.{1} supprimés",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Doit avoir au moins un chemin",
|
||||||
"ToastNameEmailRequired": "Le nom et le courriel sont requis",
|
"ToastNameEmailRequired": "Le nom et le courriel sont requis",
|
||||||
"ToastNameRequired": "Le nom est requis",
|
"ToastNameRequired": "Le nom est requis",
|
||||||
|
"ToastNewEpisodesFound": "{0} nouveaux épisodes trouvés",
|
||||||
"ToastNewUserCreatedFailed": "La création du compte à échouée : « {0} »",
|
"ToastNewUserCreatedFailed": "La création du compte à échouée : « {0} »",
|
||||||
"ToastNewUserCreatedSuccess": "Nouveau compte créé",
|
"ToastNewUserCreatedSuccess": "Nouveau compte créé",
|
||||||
"ToastNewUserLibraryError": "Au moins une bibliothèque est requise",
|
"ToastNewUserLibraryError": "Au moins une bibliothèque est requise",
|
||||||
"ToastNewUserPasswordError": "Un mot de passe est requis, seul l’utilisateur root peut avoir un mot de passe vide",
|
"ToastNewUserPasswordError": "Un mot de passe est requis, seul l’utilisateur root peut avoir un mot de passe vide",
|
||||||
"ToastNewUserTagError": "Au moins une étiquette est requise",
|
"ToastNewUserTagError": "Au moins une étiquette est requise",
|
||||||
"ToastNewUserUsernameError": "Entrez un nom d’utilisateur",
|
"ToastNewUserUsernameError": "Entrez un nom d’utilisateur",
|
||||||
|
"ToastNoNewEpisodesFound": "Aucun nouvel épisode trouvé",
|
||||||
"ToastNoUpdatesNecessary": "Aucune mise à jour nécessaire",
|
"ToastNoUpdatesNecessary": "Aucune mise à jour nécessaire",
|
||||||
"ToastNotificationCreateFailed": "La création de la notification à échouée",
|
"ToastNotificationCreateFailed": "La création de la notification à échouée",
|
||||||
"ToastNotificationDeleteFailed": "La suppression de la notification à échouée",
|
"ToastNotificationDeleteFailed": "La suppression de la notification à échouée",
|
||||||
@@ -979,6 +1026,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "Échec de la récupération du flux du podcast",
|
"ToastPodcastGetFeedFailed": "Échec de la récupération du flux du podcast",
|
||||||
"ToastPodcastNoEpisodesInFeed": "Aucun épisode trouvé dans le flux RSS",
|
"ToastPodcastNoEpisodesInFeed": "Aucun épisode trouvé dans le flux RSS",
|
||||||
"ToastPodcastNoRssFeed": "Le podcast n’a pas de flux RSS",
|
"ToastPodcastNoRssFeed": "Le podcast n’a pas de flux RSS",
|
||||||
|
"ToastProgressIsNotBeingSynced": "La progression n’est pas synchronisée, redémarrez la lecture",
|
||||||
"ToastProviderCreatedFailed": "Échec de l’ajout du fournisseur",
|
"ToastProviderCreatedFailed": "Échec de l’ajout du fournisseur",
|
||||||
"ToastProviderCreatedSuccess": "Nouveau fournisseur ajouté",
|
"ToastProviderCreatedSuccess": "Nouveau fournisseur ajouté",
|
||||||
"ToastProviderNameAndUrlRequired": "Nom et URL requis",
|
"ToastProviderNameAndUrlRequired": "Nom et URL requis",
|
||||||
@@ -1005,6 +1053,7 @@
|
|||||||
"ToastSessionCloseFailed": "Échec de la fermeture de la session",
|
"ToastSessionCloseFailed": "Échec de la fermeture de la session",
|
||||||
"ToastSessionDeleteFailed": "Échec de la suppression de session",
|
"ToastSessionDeleteFailed": "Échec de la suppression de session",
|
||||||
"ToastSessionDeleteSuccess": "Session supprimée",
|
"ToastSessionDeleteSuccess": "Session supprimée",
|
||||||
|
"ToastSleepTimerDone": "Minuterie de mise en veille terminée… zZzzZz",
|
||||||
"ToastSlugMustChange": "L’identifiant d’URL contient des caractères invalides",
|
"ToastSlugMustChange": "L’identifiant d’URL contient des caractères invalides",
|
||||||
"ToastSlugRequired": "L’identifiant d’URL est requis",
|
"ToastSlugRequired": "L’identifiant d’URL est requis",
|
||||||
"ToastSocketConnected": "WebSocket connecté",
|
"ToastSocketConnected": "WebSocket connecté",
|
||||||
|
|||||||
+26
-3
@@ -8,17 +8,18 @@
|
|||||||
"ButtonAddYourFirstLibrary": "הוסף את הספרייה הראשונה שלך",
|
"ButtonAddYourFirstLibrary": "הוסף את הספרייה הראשונה שלך",
|
||||||
"ButtonApply": "החל",
|
"ButtonApply": "החל",
|
||||||
"ButtonApplyChapters": "החל פרקים",
|
"ButtonApplyChapters": "החל פרקים",
|
||||||
"ButtonAuthors": "יוצרים",
|
"ButtonAuthors": "סופרים",
|
||||||
"ButtonBack": "חזור",
|
"ButtonBack": "חזור",
|
||||||
"ButtonBrowseForFolder": "עיין בתיקייה",
|
"ButtonBrowseForFolder": "עיין בתיקייה",
|
||||||
"ButtonCancel": "בטל",
|
"ButtonCancel": "ביטול",
|
||||||
"ButtonCancelEncode": "בטל קידוד",
|
"ButtonCancelEncode": "בטל קידוד",
|
||||||
"ButtonChangeRootPassword": "שנה סיסמת root",
|
"ButtonChangeRootPassword": "שנה סיסמת root",
|
||||||
"ButtonCheckAndDownloadNewEpisodes": "בדוק והורד פרקים חדשים",
|
"ButtonCheckAndDownloadNewEpisodes": "בדוק והורד פרקים חדשים",
|
||||||
"ButtonChooseAFolder": "בחר תיקייה",
|
"ButtonChooseAFolder": "בחר תיקייה",
|
||||||
"ButtonChooseFiles": "בחר קבצים",
|
"ButtonChooseFiles": "בחר קבצים",
|
||||||
"ButtonClearFilter": "נקה סינון",
|
"ButtonClearFilter": "נקה סינון",
|
||||||
"ButtonCloseFeed": "סגור פיד",
|
"ButtonCloseFeed": "סגור ערוץ",
|
||||||
|
"ButtonCloseSession": "סגור סשן פתוח",
|
||||||
"ButtonCollections": "אוספים",
|
"ButtonCollections": "אוספים",
|
||||||
"ButtonConfigureScanner": "הגדר סורק",
|
"ButtonConfigureScanner": "הגדר סורק",
|
||||||
"ButtonCreate": "צור",
|
"ButtonCreate": "צור",
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
"ButtonEdit": "ערוך",
|
"ButtonEdit": "ערוך",
|
||||||
"ButtonEditChapters": "ערוך פרקים",
|
"ButtonEditChapters": "ערוך פרקים",
|
||||||
"ButtonEditPodcast": "ערוך פודקאסט",
|
"ButtonEditPodcast": "ערוך פודקאסט",
|
||||||
|
"ButtonEnable": "הפעל",
|
||||||
"ButtonForceReScan": "סרוק מחדש בכוח",
|
"ButtonForceReScan": "סרוק מחדש בכוח",
|
||||||
"ButtonFullPath": "נתיב מלא",
|
"ButtonFullPath": "נתיב מלא",
|
||||||
"ButtonHide": "הסתר",
|
"ButtonHide": "הסתר",
|
||||||
@@ -46,19 +48,24 @@
|
|||||||
"ButtonNevermind": "לא משנה",
|
"ButtonNevermind": "לא משנה",
|
||||||
"ButtonNext": "הבא",
|
"ButtonNext": "הבא",
|
||||||
"ButtonNextChapter": "פרק הבא",
|
"ButtonNextChapter": "פרק הבא",
|
||||||
|
"ButtonNextItemInQueue": "פריט הבא בתור",
|
||||||
"ButtonOk": "אישור",
|
"ButtonOk": "אישור",
|
||||||
"ButtonOpenFeed": "פתח פיד",
|
"ButtonOpenFeed": "פתח פיד",
|
||||||
"ButtonOpenManager": "פתח מנהל",
|
"ButtonOpenManager": "פתח מנהל",
|
||||||
"ButtonPause": "השהה",
|
"ButtonPause": "השהה",
|
||||||
"ButtonPlay": "נגן",
|
"ButtonPlay": "נגן",
|
||||||
|
"ButtonPlayAll": "נגן הכל",
|
||||||
"ButtonPlaying": "מנגן",
|
"ButtonPlaying": "מנגן",
|
||||||
"ButtonPlaylists": "רשימות השמעה",
|
"ButtonPlaylists": "רשימות השמעה",
|
||||||
"ButtonPrevious": "קודם",
|
"ButtonPrevious": "קודם",
|
||||||
"ButtonPreviousChapter": "פרק קודם",
|
"ButtonPreviousChapter": "פרק קודם",
|
||||||
|
"ButtonProbeAudioFile": "בדוק קובץ אודיו",
|
||||||
"ButtonPurgeAllCache": "נקה את כל המטמון",
|
"ButtonPurgeAllCache": "נקה את כל המטמון",
|
||||||
"ButtonPurgeItemsCache": "נקה את מטמון הפריטים",
|
"ButtonPurgeItemsCache": "נקה את מטמון הפריטים",
|
||||||
"ButtonQueueAddItem": "הוסף לתור",
|
"ButtonQueueAddItem": "הוסף לתור",
|
||||||
"ButtonQueueRemoveItem": "הסר מהתור",
|
"ButtonQueueRemoveItem": "הסר מהתור",
|
||||||
|
"ButtonQuickEmbed": "הטמעה מהירה",
|
||||||
|
"ButtonQuickEmbedMetadata": "הטמעת מטא נתונים מהירה",
|
||||||
"ButtonQuickMatch": "התאמה מהירה",
|
"ButtonQuickMatch": "התאמה מהירה",
|
||||||
"ButtonReScan": "סרוק מחדש",
|
"ButtonReScan": "סרוק מחדש",
|
||||||
"ButtonRead": "קרא",
|
"ButtonRead": "קרא",
|
||||||
@@ -88,8 +95,10 @@
|
|||||||
"ButtonShow": "הצג",
|
"ButtonShow": "הצג",
|
||||||
"ButtonStartM4BEncode": "התחל קידוד M4B",
|
"ButtonStartM4BEncode": "התחל קידוד M4B",
|
||||||
"ButtonStartMetadataEmbed": "התחל הטמעת מטא-נתונים",
|
"ButtonStartMetadataEmbed": "התחל הטמעת מטא-נתונים",
|
||||||
|
"ButtonStats": "סטטיסטיקות",
|
||||||
"ButtonSubmit": "שלח",
|
"ButtonSubmit": "שלח",
|
||||||
"ButtonTest": "בדיקה",
|
"ButtonTest": "בדיקה",
|
||||||
|
"ButtonUnlinkOpenId": "נתק OpenID",
|
||||||
"ButtonUpload": "העלה",
|
"ButtonUpload": "העלה",
|
||||||
"ButtonUploadBackup": "העלה גיבוי",
|
"ButtonUploadBackup": "העלה גיבוי",
|
||||||
"ButtonUploadCover": "העלה כריכה",
|
"ButtonUploadCover": "העלה כריכה",
|
||||||
@@ -102,6 +111,7 @@
|
|||||||
"ErrorUploadFetchMetadataNoResults": "לא ניתן לשלוף מטא-נתונים - נסה לעדכן כותרת ו/או יוצר",
|
"ErrorUploadFetchMetadataNoResults": "לא ניתן לשלוף מטא-נתונים - נסה לעדכן כותרת ו/או יוצר",
|
||||||
"ErrorUploadLacksTitle": "חובה לתת כותרת",
|
"ErrorUploadLacksTitle": "חובה לתת כותרת",
|
||||||
"HeaderAccount": "חשבון",
|
"HeaderAccount": "חשבון",
|
||||||
|
"HeaderAddCustomMetadataProvider": "הוסף ספק מטא-נתונים מותאם אישית",
|
||||||
"HeaderAdvanced": "מתקדם",
|
"HeaderAdvanced": "מתקדם",
|
||||||
"HeaderAppriseNotificationSettings": "הגדרות התראות של Apprise",
|
"HeaderAppriseNotificationSettings": "הגדרות התראות של Apprise",
|
||||||
"HeaderAudioTracks": "רצועות קול",
|
"HeaderAudioTracks": "רצועות קול",
|
||||||
@@ -147,13 +157,17 @@
|
|||||||
"HeaderMetadataToEmbed": "מטא-נתונים להטמעה",
|
"HeaderMetadataToEmbed": "מטא-נתונים להטמעה",
|
||||||
"HeaderNewAccount": "חשבון חדש",
|
"HeaderNewAccount": "חשבון חדש",
|
||||||
"HeaderNewLibrary": "ספרייה חדשה",
|
"HeaderNewLibrary": "ספרייה חדשה",
|
||||||
|
"HeaderNotificationCreate": "צור התראה",
|
||||||
|
"HeaderNotificationUpdate": "עדכון התראה",
|
||||||
"HeaderNotifications": "התראות",
|
"HeaderNotifications": "התראות",
|
||||||
"HeaderOpenIDConnectAuthentication": "אימות OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "אימות OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "פתח הפעלות האזנה",
|
||||||
"HeaderOpenRSSFeed": "פתח ערוץ RSS",
|
"HeaderOpenRSSFeed": "פתח ערוץ RSS",
|
||||||
"HeaderOtherFiles": "קבצים אחרים",
|
"HeaderOtherFiles": "קבצים אחרים",
|
||||||
"HeaderPasswordAuthentication": "אימות סיסמה",
|
"HeaderPasswordAuthentication": "אימות סיסמה",
|
||||||
"HeaderPermissions": "הרשאות",
|
"HeaderPermissions": "הרשאות",
|
||||||
"HeaderPlayerQueue": "תור ניגון",
|
"HeaderPlayerQueue": "תור ניגון",
|
||||||
|
"HeaderPlayerSettings": "הגדרות נגן",
|
||||||
"HeaderPlaylist": "רשימת השמעה",
|
"HeaderPlaylist": "רשימת השמעה",
|
||||||
"HeaderPlaylistItems": "פריטי רשימת השמעה",
|
"HeaderPlaylistItems": "פריטי רשימת השמעה",
|
||||||
"HeaderPodcastsToAdd": "פודקאסטים להוספה",
|
"HeaderPodcastsToAdd": "פודקאסטים להוספה",
|
||||||
@@ -165,6 +179,7 @@
|
|||||||
"HeaderRemoveEpisodes": "הסר {0} פרקים",
|
"HeaderRemoveEpisodes": "הסר {0} פרקים",
|
||||||
"HeaderSavedMediaProgress": "התקדמות מדיה שמורה",
|
"HeaderSavedMediaProgress": "התקדמות מדיה שמורה",
|
||||||
"HeaderSchedule": "תיזמון",
|
"HeaderSchedule": "תיזמון",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "תזמן הורדת פרקים אוטומטית",
|
||||||
"HeaderScheduleLibraryScans": "קבע סריקות ספרייה אוטומטיות",
|
"HeaderScheduleLibraryScans": "קבע סריקות ספרייה אוטומטיות",
|
||||||
"HeaderSession": "הפעלה",
|
"HeaderSession": "הפעלה",
|
||||||
"HeaderSetBackupSchedule": "קבע לוח זמנים לגיבוי",
|
"HeaderSetBackupSchedule": "קבע לוח זמנים לגיבוי",
|
||||||
@@ -190,6 +205,9 @@
|
|||||||
"HeaderYearReview": "שנת {0} בסקירה",
|
"HeaderYearReview": "שנת {0} בסקירה",
|
||||||
"HeaderYourStats": "הסטטיסטיקות שלך",
|
"HeaderYourStats": "הסטטיסטיקות שלך",
|
||||||
"LabelAbridged": "מקוצר",
|
"LabelAbridged": "מקוצר",
|
||||||
|
"LabelAbridgedChecked": "מקוצר (מסומן)",
|
||||||
|
"LabelAbridgedUnchecked": "בלתי מקוצר (לא מסומן)",
|
||||||
|
"LabelAccessibleBy": "נגיש על ידי",
|
||||||
"LabelAccountType": "סוג חשבון",
|
"LabelAccountType": "סוג חשבון",
|
||||||
"LabelAccountTypeAdmin": "מנהל",
|
"LabelAccountTypeAdmin": "מנהל",
|
||||||
"LabelAccountTypeGuest": "אורח",
|
"LabelAccountTypeGuest": "אורח",
|
||||||
@@ -200,13 +218,18 @@
|
|||||||
"LabelAddToPlaylist": "הוסף לרשימת השמעה",
|
"LabelAddToPlaylist": "הוסף לרשימת השמעה",
|
||||||
"LabelAddToPlaylistBatch": "הוסף {0} פריטים לרשימת השמעה",
|
"LabelAddToPlaylistBatch": "הוסף {0} פריטים לרשימת השמעה",
|
||||||
"LabelAddedAt": "נוסף בתאריך",
|
"LabelAddedAt": "נוסף בתאריך",
|
||||||
|
"LabelAddedDate": "נוסף ב-{0}",
|
||||||
"LabelAdminUsersOnly": "רק מנהלים",
|
"LabelAdminUsersOnly": "רק מנהלים",
|
||||||
"LabelAll": "הכל",
|
"LabelAll": "הכל",
|
||||||
"LabelAllUsers": "כל המשתמשים",
|
"LabelAllUsers": "כל המשתמשים",
|
||||||
"LabelAllUsersExcludingGuests": "כל המשתמשים, ללא אורחים",
|
"LabelAllUsersExcludingGuests": "כל המשתמשים, ללא אורחים",
|
||||||
"LabelAllUsersIncludingGuests": "כל המשתמשים כולל אורחים",
|
"LabelAllUsersIncludingGuests": "כל המשתמשים כולל אורחים",
|
||||||
"LabelAlreadyInYourLibrary": "כבר קיים בספרייה שלך",
|
"LabelAlreadyInYourLibrary": "כבר קיים בספרייה שלך",
|
||||||
|
"LabelApiToken": "טוקן API",
|
||||||
"LabelAppend": "הוסף לסוף",
|
"LabelAppend": "הוסף לסוף",
|
||||||
|
"LabelAudioBitrate": "קצב סיביות (לדוגמא 128k)",
|
||||||
|
"LabelAudioChannels": "ערוצי קול (1 או 2)",
|
||||||
|
"LabelAudioCodec": "קידוד קול",
|
||||||
"LabelAuthor": "יוצר",
|
"LabelAuthor": "יוצר",
|
||||||
"LabelAuthorFirstLast": "יוצר (שם פרטי שם משפחה)",
|
"LabelAuthorFirstLast": "יוצר (שם פרטי שם משפחה)",
|
||||||
"LabelAuthorLastFirst": "יוצר (שם משפחה, שם פרטי)",
|
"LabelAuthorLastFirst": "יוצר (שם משפחה, שם פרטי)",
|
||||||
|
|||||||
+23
-12
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Ažuriraj obavijest",
|
"HeaderNotificationUpdate": "Ažuriraj obavijest",
|
||||||
"HeaderNotifications": "Obavijesti",
|
"HeaderNotifications": "Obavijesti",
|
||||||
"HeaderOpenIDConnectAuthentication": "Prijava na OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Prijava na OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Otvorene sesije slušanja",
|
||||||
"HeaderOpenRSSFeed": "Otvori RSS izvor",
|
"HeaderOpenRSSFeed": "Otvori RSS izvor",
|
||||||
"HeaderOtherFiles": "Druge datoteke",
|
"HeaderOtherFiles": "Druge datoteke",
|
||||||
"HeaderPasswordAuthentication": "Provjera autentičnosti zaporkom",
|
"HeaderPasswordAuthentication": "Provjera autentičnosti zaporkom",
|
||||||
@@ -226,6 +227,7 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Svi korisnici osim gostiju",
|
"LabelAllUsersExcludingGuests": "Svi korisnici osim gostiju",
|
||||||
"LabelAllUsersIncludingGuests": "Svi korisnici uključujući i goste",
|
"LabelAllUsersIncludingGuests": "Svi korisnici uključujući i goste",
|
||||||
"LabelAlreadyInYourLibrary": "Već u vašoj knjižnici",
|
"LabelAlreadyInYourLibrary": "Već u vašoj knjižnici",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Pridodaj",
|
"LabelAppend": "Pridodaj",
|
||||||
"LabelAudioBitrate": "Kvaliteta zvučnog zapisa (npr. 128k)",
|
"LabelAudioBitrate": "Kvaliteta zvučnog zapisa (npr. 128k)",
|
||||||
"LabelAudioChannels": "Broj zvučnih kanala (1 ili 2)",
|
"LabelAudioChannels": "Broj zvučnih kanala (1 ili 2)",
|
||||||
@@ -252,9 +254,9 @@
|
|||||||
"LabelBackupsNumberToKeepHelp": "Moguće je izbrisati samo jednu po jednu sigurnosnu kopiju, ako ih već imate više trebat ćete ih ručno ukloniti.",
|
"LabelBackupsNumberToKeepHelp": "Moguće je izbrisati samo jednu po jednu sigurnosnu kopiju, ako ih već imate više trebat ćete ih ručno ukloniti.",
|
||||||
"LabelBitrate": "Protok",
|
"LabelBitrate": "Protok",
|
||||||
"LabelBonus": "Bonus",
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "knjiga/e",
|
"LabelBooks": "Knjige",
|
||||||
"LabelButtonText": "Tekst gumba",
|
"LabelButtonText": "Tekst gumba",
|
||||||
"LabelByAuthor": "po {0}",
|
"LabelByAuthor": "autor: {0}",
|
||||||
"LabelChangePassword": "Promijeni zaporku",
|
"LabelChangePassword": "Promijeni zaporku",
|
||||||
"LabelChannels": "Kanali",
|
"LabelChannels": "Kanali",
|
||||||
"LabelChapterCount": "{0} Poglavlje/a",
|
"LabelChapterCount": "{0} Poglavlje/a",
|
||||||
@@ -268,8 +270,8 @@
|
|||||||
"LabelCollapseSeries": "Serijale prikaži sažeto",
|
"LabelCollapseSeries": "Serijale prikaži sažeto",
|
||||||
"LabelCollapseSubSeries": "Podserijale prikaži sažeto",
|
"LabelCollapseSubSeries": "Podserijale prikaži sažeto",
|
||||||
"LabelCollection": "Zbirka",
|
"LabelCollection": "Zbirka",
|
||||||
"LabelCollections": "Zbirka/i",
|
"LabelCollections": "Zbirke",
|
||||||
"LabelComplete": "Dovršeno",
|
"LabelComplete": "Potpuno",
|
||||||
"LabelConfirmPassword": "Potvrda zaporke",
|
"LabelConfirmPassword": "Potvrda zaporke",
|
||||||
"LabelContinueListening": "Nastavi slušati",
|
"LabelContinueListening": "Nastavi slušati",
|
||||||
"LabelContinueReading": "Nastavi čitati",
|
"LabelContinueReading": "Nastavi čitati",
|
||||||
@@ -358,6 +360,7 @@
|
|||||||
"LabelFontScale": "Veličina slova",
|
"LabelFontScale": "Veličina slova",
|
||||||
"LabelFontStrikethrough": "Precrtano",
|
"LabelFontStrikethrough": "Precrtano",
|
||||||
"LabelFormat": "Format",
|
"LabelFormat": "Format",
|
||||||
|
"LabelFull": "Cijeli",
|
||||||
"LabelGenre": "Žanr",
|
"LabelGenre": "Žanr",
|
||||||
"LabelGenres": "Žanrovi",
|
"LabelGenres": "Žanrovi",
|
||||||
"LabelHardDeleteFile": "Obriši datoteku zauvijek",
|
"LabelHardDeleteFile": "Obriši datoteku zauvijek",
|
||||||
@@ -462,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Naziv OpenID zahtjeva koji sadrži popis korisnikovih grupa. Često se naziva <code>groups</code>. <b>Ako se konfigurira</b>, aplikacija će automatski dodijeliti uloge temeljem korisnikovih članstava u grupama, pod uvjetom da se iste zovu 'admin', 'user' ili 'guest' u zahtjevu (ne razlikuju se velika i mala slova). Zahtjev treba sadržavati popis i ako je korisnik član više grupa, aplikacija će dodijeliti ulogu koja odgovara najvišoj razini pristupa. Ukoliko se niti jedna grupa ne podudara, pristup će biti onemogućen.",
|
"LabelOpenIDGroupClaimDescription": "Naziv OpenID zahtjeva koji sadrži popis korisnikovih grupa. Često se naziva <code>groups</code>. <b>Ako se konfigurira</b>, aplikacija će automatski dodijeliti uloge temeljem korisnikovih članstava u grupama, pod uvjetom da se iste zovu 'admin', 'user' ili 'guest' u zahtjevu (ne razlikuju se velika i mala slova). Zahtjev treba sadržavati popis i ako je korisnik član više grupa, aplikacija će dodijeliti ulogu koja odgovara najvišoj razini pristupa. Ukoliko se niti jedna grupa ne podudara, pristup će biti onemogućen.",
|
||||||
"LabelOpenRSSFeed": "Otvori RSS Feed",
|
"LabelOpenRSSFeed": "Otvori RSS Feed",
|
||||||
"LabelOverwrite": "Prepiši",
|
"LabelOverwrite": "Prepiši",
|
||||||
|
"LabelPaginationPageXOfY": "Stranica {0} od {1}",
|
||||||
"LabelPassword": "Zaporka",
|
"LabelPassword": "Zaporka",
|
||||||
"LabelPath": "Putanja",
|
"LabelPath": "Putanja",
|
||||||
"LabelPermanent": "Trajno",
|
"LabelPermanent": "Trajno",
|
||||||
"LabelPermissionsAccessAllLibraries": "Ima pristup svim knjižnicama",
|
"LabelPermissionsAccessAllLibraries": "Ima pristup svim knjižnicama",
|
||||||
"LabelPermissionsAccessAllTags": "Ima pristup svim oznakama",
|
"LabelPermissionsAccessAllTags": "Ima pristup svim oznakama",
|
||||||
"LabelPermissionsAccessExplicitContent": "Ima pristup eksplicitnom sadržaju",
|
"LabelPermissionsAccessExplicitContent": "Ima pristup eksplicitnom sadržaju",
|
||||||
|
"LabelPermissionsCreateEreader": "Može stvoriti e-čitač",
|
||||||
"LabelPermissionsDelete": "Smije brisati",
|
"LabelPermissionsDelete": "Smije brisati",
|
||||||
"LabelPermissionsDownload": "Smije preuzimati",
|
"LabelPermissionsDownload": "Smije preuzimati",
|
||||||
"LabelPermissionsUpdate": "Smije ažurirati",
|
"LabelPermissionsUpdate": "Smije ažurirati",
|
||||||
@@ -491,8 +496,8 @@
|
|||||||
"LabelPubDate": "Datum izdavanja",
|
"LabelPubDate": "Datum izdavanja",
|
||||||
"LabelPublishYear": "Godina objavljivanja",
|
"LabelPublishYear": "Godina objavljivanja",
|
||||||
"LabelPublishedDate": "Objavljeno {0}",
|
"LabelPublishedDate": "Objavljeno {0}",
|
||||||
"LabelPublishedDecade": "Desetljeće objavljivanja",
|
"LabelPublishedDecade": "Desetljeće izdanja",
|
||||||
"LabelPublishedDecades": "Desetljeća objavljivanja",
|
"LabelPublishedDecades": "Desetljeća izdanja",
|
||||||
"LabelPublisher": "Izdavač",
|
"LabelPublisher": "Izdavač",
|
||||||
"LabelPublishers": "Izdavači",
|
"LabelPublishers": "Izdavači",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "Prilagođena adresa e-pošte vlasnika",
|
"LabelRSSFeedCustomOwnerEmail": "Prilagođena adresa e-pošte vlasnika",
|
||||||
@@ -527,10 +532,10 @@
|
|||||||
"LabelSelectAllEpisodes": "Označi sve nastavke",
|
"LabelSelectAllEpisodes": "Označi sve nastavke",
|
||||||
"LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka",
|
"LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka",
|
||||||
"LabelSelectUsers": "Označi korisnike",
|
"LabelSelectUsers": "Označi korisnike",
|
||||||
"LabelSendEbookToDevice": "Pošalji e-knjigu",
|
"LabelSendEbookToDevice": "Pošalji e-knjigu …",
|
||||||
"LabelSequence": "Slijed",
|
"LabelSequence": "Slijed",
|
||||||
"LabelSerial": "Serijal",
|
"LabelSerial": "Serijal",
|
||||||
"LabelSeries": "Serijal/a",
|
"LabelSeries": "Serijal",
|
||||||
"LabelSeriesName": "Ime serijala",
|
"LabelSeriesName": "Ime serijala",
|
||||||
"LabelSeriesProgress": "Napredak u serijalu",
|
"LabelSeriesProgress": "Napredak u serijalu",
|
||||||
"LabelServerLogLevel": "Razina zapisa poslužitelja",
|
"LabelServerLogLevel": "Razina zapisa poslužitelja",
|
||||||
@@ -558,8 +563,11 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Serijali koji se sastoje od samo jedne knjige neće se prikazivati na stranici serijala i na policama početne stranice.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Serijali koji se sastoje od samo jedne knjige neće se prikazivati na stranici serijala i na policama početne stranice.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Prikaži početnu stranicu kao policu s knjigama",
|
"LabelSettingsHomePageBookshelfView": "Prikaži početnu stranicu kao policu s knjigama",
|
||||||
"LabelSettingsLibraryBookshelfView": "Prikaži knjižnicu kao policu s knjigama",
|
"LabelSettingsLibraryBookshelfView": "Prikaži knjižnicu kao policu s knjigama",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Postotak dovršenosti veći od",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Preostalo vrijeme je manje od (sekundi)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Označi medij dovršenim kada",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči ranije knjige u funkciji Nastavi serijal",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči ranije knjige u funkciji Nastavi serijal",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako uključite ovu opciju, serijal će vam se nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako se ova opcija uključi serijal će nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.",
|
||||||
"LabelSettingsParseSubtitles": "Raščlani podnaslove",
|
"LabelSettingsParseSubtitles": "Raščlani podnaslove",
|
||||||
"LabelSettingsParseSubtitlesHelp": "Iz naziva mape zvučne knjige raščlanjuje podnaslov.<br>Podnaslov mora biti odvojen s \" - \"<br>npr. \"Naslov knjige - Ovo je podnaslov\" imat će podnaslov \"Ovo je podnaslov\"",
|
"LabelSettingsParseSubtitlesHelp": "Iz naziva mape zvučne knjige raščlanjuje podnaslov.<br>Podnaslov mora biti odvojen s \" - \"<br>npr. \"Naslov knjige - Ovo je podnaslov\" imat će podnaslov \"Ovo je podnaslov\"",
|
||||||
"LabelSettingsPreferMatchedMetadata": "Daj prednost meta-podatcima prepoznatih stavki",
|
"LabelSettingsPreferMatchedMetadata": "Daj prednost meta-podatcima prepoznatih stavki",
|
||||||
@@ -639,7 +647,7 @@
|
|||||||
"LabelTotalTimeListened": "Sveukupno vrijeme slušanja",
|
"LabelTotalTimeListened": "Sveukupno vrijeme slušanja",
|
||||||
"LabelTrackFromFilename": "Naslov iz imena datoteke",
|
"LabelTrackFromFilename": "Naslov iz imena datoteke",
|
||||||
"LabelTrackFromMetadata": "Naslov iz meta-podataka",
|
"LabelTrackFromMetadata": "Naslov iz meta-podataka",
|
||||||
"LabelTracks": "Naslovi",
|
"LabelTracks": "Zvučni zapisi",
|
||||||
"LabelTracksMultiTrack": "Više zvučnih zapisa",
|
"LabelTracksMultiTrack": "Više zvučnih zapisa",
|
||||||
"LabelTracksNone": "Nema zapisa",
|
"LabelTracksNone": "Nema zapisa",
|
||||||
"LabelTracksSingleTrack": "Jedan zvučni zapis",
|
"LabelTracksSingleTrack": "Jedan zvučni zapis",
|
||||||
@@ -655,6 +663,7 @@
|
|||||||
"LabelUpdateDetailsHelp": "Dopusti prepisivanje postojećih podataka za odabrane knjige kada se prepoznaju",
|
"LabelUpdateDetailsHelp": "Dopusti prepisivanje postojećih podataka za odabrane knjige kada se prepoznaju",
|
||||||
"LabelUpdatedAt": "Ažurirano",
|
"LabelUpdatedAt": "Ažurirano",
|
||||||
"LabelUploaderDragAndDrop": "Pritisni i prevuci datoteke ili mape",
|
"LabelUploaderDragAndDrop": "Pritisni i prevuci datoteke ili mape",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Pritisni i prevuci datoteke",
|
||||||
"LabelUploaderDropFiles": "Ispusti datoteke",
|
"LabelUploaderDropFiles": "Ispusti datoteke",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Automatski dohvati naslov, autora i serijal",
|
"LabelUploaderItemFetchMetadataHelp": "Automatski dohvati naslov, autora i serijal",
|
||||||
"LabelUseAdvancedOptions": "Koristi se naprednim opcijama",
|
"LabelUseAdvancedOptions": "Koristi se naprednim opcijama",
|
||||||
@@ -670,6 +679,8 @@
|
|||||||
"LabelViewPlayerSettings": "Pogledaj postavke reproduktora",
|
"LabelViewPlayerSettings": "Pogledaj postavke reproduktora",
|
||||||
"LabelViewQueue": "Pogledaj redoslijed izvođenja reproduktora",
|
"LabelViewQueue": "Pogledaj redoslijed izvođenja reproduktora",
|
||||||
"LabelVolume": "Glasnoća",
|
"LabelVolume": "Glasnoća",
|
||||||
|
"LabelWebRedirectURLsDescription": "Autoriziraj ove URL-ove u svom pružatelju OAuth ovjere kako bi omogućio preusmjeravanje natrag na web-aplikaciju nakon prijave:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Podmapa za URL-ove preusmjeravanja",
|
||||||
"LabelWeekdaysToRun": "Dani u tjednu za pokretanje",
|
"LabelWeekdaysToRun": "Dani u tjednu za pokretanje",
|
||||||
"LabelXBooks": "{0} knjiga",
|
"LabelXBooks": "{0} knjiga",
|
||||||
"LabelXItems": "{0} stavki",
|
"LabelXItems": "{0} stavki",
|
||||||
@@ -740,7 +751,7 @@
|
|||||||
"MessageConfirmSendEbookToDevice": "Sigurno želite poslati {0} e-knjiga/u \"{1}\" na uređaj \"{2}\"?",
|
"MessageConfirmSendEbookToDevice": "Sigurno želite poslati {0} e-knjiga/u \"{1}\" na uređaj \"{2}\"?",
|
||||||
"MessageConfirmUnlinkOpenId": "Sigurno želite odspojiti ovog korisnika s OpenID-ja?",
|
"MessageConfirmUnlinkOpenId": "Sigurno želite odspojiti ovog korisnika s OpenID-ja?",
|
||||||
"MessageDownloadingEpisode": "Preuzimam nastavak",
|
"MessageDownloadingEpisode": "Preuzimam nastavak",
|
||||||
"MessageDragFilesIntoTrackOrder": "Ispravi redoslijed zapisa prevlačenje datoteka",
|
"MessageDragFilesIntoTrackOrder": "Prevlačenjem datoteka složite pravilan redoslijed",
|
||||||
"MessageEmbedFailed": "Ugrađivanje nije uspjelo!",
|
"MessageEmbedFailed": "Ugrađivanje nije uspjelo!",
|
||||||
"MessageEmbedFinished": "Ugrađivanje je dovršeno!",
|
"MessageEmbedFinished": "Ugrađivanje je dovršeno!",
|
||||||
"MessageEmbedQueue": "Ugrađivanje meta-podataka dodano u red obrade ({0} u redu)",
|
"MessageEmbedQueue": "Ugrađivanje meta-podataka dodano u red obrade ({0} u redu)",
|
||||||
@@ -805,7 +816,7 @@
|
|||||||
"MessagePlaylistCreateFromCollection": "Stvori popis za izvođenje od zbirke",
|
"MessagePlaylistCreateFromCollection": "Stvori popis za izvođenje od zbirke",
|
||||||
"MessagePleaseWait": "Molimo pričekajte...",
|
"MessagePleaseWait": "Molimo pričekajte...",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nema adresu RSS izvora za prepoznavanje",
|
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nema adresu RSS izvora za prepoznavanje",
|
||||||
"MessagePodcastSearchField": "Unesite upit za pretragu ili URL RSS izvora",
|
"MessagePodcastSearchField": "Upišite izraz za pretraživanje ili URL RSS izvora",
|
||||||
"MessageQuickEmbedInProgress": "Brzo ugrađivanje u tijeku",
|
"MessageQuickEmbedInProgress": "Brzo ugrađivanje u tijeku",
|
||||||
"MessageQuickEmbedQueue": "Dodano u red za brzo ugrađivanje ({0} u redu izvođenja)",
|
"MessageQuickEmbedQueue": "Dodano u red za brzo ugrađivanje ({0} u redu izvođenja)",
|
||||||
"MessageQuickMatchAllEpisodes": "Brzo prepoznavanje svih nastavaka",
|
"MessageQuickMatchAllEpisodes": "Brzo prepoznavanje svih nastavaka",
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
"ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése",
|
"ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése",
|
||||||
"ButtonQueueAddItem": "Hozzáadás a sorhoz",
|
"ButtonQueueAddItem": "Hozzáadás a sorhoz",
|
||||||
"ButtonQueueRemoveItem": "Eltávolítás a sorból",
|
"ButtonQueueRemoveItem": "Eltávolítás a sorból",
|
||||||
|
"ButtonQuickEmbed": "Gyors beágyazás",
|
||||||
"ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása",
|
"ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása",
|
||||||
"ButtonQuickMatch": "Gyors egyeztetés",
|
"ButtonQuickMatch": "Gyors egyeztetés",
|
||||||
"ButtonReScan": "Újraszkennelés",
|
"ButtonReScan": "Újraszkennelés",
|
||||||
@@ -343,7 +344,7 @@
|
|||||||
"LabelHasSupplementaryEbook": "Van kiegészítő e-könyve",
|
"LabelHasSupplementaryEbook": "Van kiegészítő e-könyve",
|
||||||
"LabelHideSubtitles": "Alcím elrejtése",
|
"LabelHideSubtitles": "Alcím elrejtése",
|
||||||
"LabelHighestPriority": "Legmagasabb prioritás",
|
"LabelHighestPriority": "Legmagasabb prioritás",
|
||||||
"LabelHost": "Házigazda",
|
"LabelHost": "Kiszolgáló",
|
||||||
"LabelHour": "Óra",
|
"LabelHour": "Óra",
|
||||||
"LabelHours": "Órák",
|
"LabelHours": "Órák",
|
||||||
"LabelIcon": "Ikon",
|
"LabelIcon": "Ikon",
|
||||||
|
|||||||
+55
-7
@@ -66,13 +66,13 @@
|
|||||||
"ButtonPurgeItemsCache": "Elimina la Cache selezionata",
|
"ButtonPurgeItemsCache": "Elimina la Cache selezionata",
|
||||||
"ButtonQueueAddItem": "Aggiungi alla Coda",
|
"ButtonQueueAddItem": "Aggiungi alla Coda",
|
||||||
"ButtonQueueRemoveItem": "Rimuovi dalla Coda",
|
"ButtonQueueRemoveItem": "Rimuovi dalla Coda",
|
||||||
"ButtonQuickEmbed": "Quick Embed",
|
"ButtonQuickEmbed": "Incorporazione Rapida",
|
||||||
"ButtonQuickEmbedMetadata": "Incorporamento rapido Metadati",
|
"ButtonQuickEmbedMetadata": "Incorporamento rapido Metadati",
|
||||||
"ButtonQuickMatch": "Controlla Metadata Auto",
|
"ButtonQuickMatch": "Controlla Metadata Auto",
|
||||||
"ButtonReScan": "Ri-scansiona",
|
"ButtonReScan": "Ri-scansiona",
|
||||||
"ButtonRead": "Leggi",
|
"ButtonRead": "Leggi",
|
||||||
"ButtonReadLess": "Leggi di Meno",
|
"ButtonReadLess": "Riduci",
|
||||||
"ButtonReadMore": "Leggi di Più",
|
"ButtonReadMore": "Espandi",
|
||||||
"ButtonRefresh": "Aggiorna",
|
"ButtonRefresh": "Aggiorna",
|
||||||
"ButtonRemove": "Rimuovi",
|
"ButtonRemove": "Rimuovi",
|
||||||
"ButtonRemoveAll": "Rimuovi Tutto",
|
"ButtonRemoveAll": "Rimuovi Tutto",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Aggiornamento della notifica",
|
"HeaderNotificationUpdate": "Aggiornamento della notifica",
|
||||||
"HeaderNotifications": "Notifiche",
|
"HeaderNotifications": "Notifiche",
|
||||||
"HeaderOpenIDConnectAuthentication": "Autenticazione OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Autenticazione OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Apri sessioni di ascolto",
|
||||||
"HeaderOpenRSSFeed": "Apri il flusso RSS",
|
"HeaderOpenRSSFeed": "Apri il flusso RSS",
|
||||||
"HeaderOtherFiles": "Altri File",
|
"HeaderOtherFiles": "Altri File",
|
||||||
"HeaderPasswordAuthentication": "Autenticazione della password",
|
"HeaderPasswordAuthentication": "Autenticazione della password",
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Rimuovi {0} Episodi",
|
"HeaderRemoveEpisodes": "Rimuovi {0} Episodi",
|
||||||
"HeaderSavedMediaProgress": "Progressi salvati",
|
"HeaderSavedMediaProgress": "Progressi salvati",
|
||||||
"HeaderSchedule": "Schedula",
|
"HeaderSchedule": "Schedula",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Imposta il download automatico degli episodi",
|
||||||
"HeaderScheduleLibraryScans": "Schedula la scansione della libreria",
|
"HeaderScheduleLibraryScans": "Schedula la scansione della libreria",
|
||||||
"HeaderSession": "Sessione",
|
"HeaderSession": "Sessione",
|
||||||
"HeaderSetBackupSchedule": "Imposta programmazione Backup",
|
"HeaderSetBackupSchedule": "Imposta programmazione Backup",
|
||||||
@@ -218,13 +220,14 @@
|
|||||||
"LabelAddToPlaylist": "Aggiungi alla playlist",
|
"LabelAddToPlaylist": "Aggiungi alla playlist",
|
||||||
"LabelAddToPlaylistBatch": "Aggiungi {0} file alla Playlist",
|
"LabelAddToPlaylistBatch": "Aggiungi {0} file alla Playlist",
|
||||||
"LabelAddedAt": "Aggiunto il",
|
"LabelAddedAt": "Aggiunto il",
|
||||||
"LabelAddedDate": "{0} aggiunti",
|
"LabelAddedDate": "Aggiunti {0}",
|
||||||
"LabelAdminUsersOnly": "Solo utenti Amministratori",
|
"LabelAdminUsersOnly": "Solo utenti Amministratori",
|
||||||
"LabelAll": "Tutti",
|
"LabelAll": "Tutti",
|
||||||
"LabelAllUsers": "Tutti gli Utenti",
|
"LabelAllUsers": "Tutti gli Utenti",
|
||||||
"LabelAllUsersExcludingGuests": "Tutti gli Utenti Esclusi gli ospiti",
|
"LabelAllUsersExcludingGuests": "Tutti gli Utenti Esclusi gli ospiti",
|
||||||
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
|
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
|
||||||
"LabelAlreadyInYourLibrary": "Già esistente nella libreria",
|
"LabelAlreadyInYourLibrary": "Già esistente nella libreria",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Appese",
|
"LabelAppend": "Appese",
|
||||||
"LabelAudioBitrate": "Audio Bitrate (es. 128k)",
|
"LabelAudioBitrate": "Audio Bitrate (es. 128k)",
|
||||||
"LabelAudioChannels": "Canali Audio (1 o 2)",
|
"LabelAudioChannels": "Canali Audio (1 o 2)",
|
||||||
@@ -250,15 +253,18 @@
|
|||||||
"LabelBackupsNumberToKeep": "Numero di backup da mantenere",
|
"LabelBackupsNumberToKeep": "Numero di backup da mantenere",
|
||||||
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
|
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
|
||||||
"LabelBitrate": "Velocità di trasmissione",
|
"LabelBitrate": "Velocità di trasmissione",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Libri",
|
"LabelBooks": "Libri",
|
||||||
"LabelButtonText": "Buttone Testo",
|
"LabelButtonText": "Buttone Testo",
|
||||||
"LabelByAuthor": "da {0}",
|
"LabelByAuthor": "da {0}",
|
||||||
"LabelChangePassword": "Cambia Password",
|
"LabelChangePassword": "Cambia Password",
|
||||||
"LabelChannels": "Canali",
|
"LabelChannels": "Canali",
|
||||||
|
"LabelChapterCount": "{0} Capitoli",
|
||||||
"LabelChapterTitle": "Titoli dei Capitoli",
|
"LabelChapterTitle": "Titoli dei Capitoli",
|
||||||
"LabelChapters": "Capitoli",
|
"LabelChapters": "Capitoli",
|
||||||
"LabelChaptersFound": "Capitoli Trovati",
|
"LabelChaptersFound": "Capitoli Trovati",
|
||||||
"LabelClickForMoreInfo": "Click per altre Info",
|
"LabelClickForMoreInfo": "Click per altre Info",
|
||||||
|
"LabelClickToUseCurrentValue": "Clicca per usare il valore corrente",
|
||||||
"LabelClosePlayer": "Chiudi player",
|
"LabelClosePlayer": "Chiudi player",
|
||||||
"LabelCodec": "Codec",
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Comprimi Serie",
|
"LabelCollapseSeries": "Comprimi Serie",
|
||||||
@@ -320,9 +326,13 @@
|
|||||||
"LabelEnd": "Fine",
|
"LabelEnd": "Fine",
|
||||||
"LabelEndOfChapter": "Fine Capitolo",
|
"LabelEndOfChapter": "Fine Capitolo",
|
||||||
"LabelEpisode": "Episodio",
|
"LabelEpisode": "Episodio",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Episode non linkati nel RSS feed",
|
||||||
|
"LabelEpisodeNumber": "Episodio #{0}",
|
||||||
"LabelEpisodeTitle": "Titolo Episodio",
|
"LabelEpisodeTitle": "Titolo Episodio",
|
||||||
"LabelEpisodeType": "Tipo Episodio",
|
"LabelEpisodeType": "Tipo Episodio",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "URL dell'episodio dal RSS feed",
|
||||||
"LabelEpisodes": "Episodi",
|
"LabelEpisodes": "Episodi",
|
||||||
|
"LabelEpisodic": "Episodico",
|
||||||
"LabelExample": "Esempio",
|
"LabelExample": "Esempio",
|
||||||
"LabelExpandSeries": "Espandi Serie",
|
"LabelExpandSeries": "Espandi Serie",
|
||||||
"LabelExpandSubSeries": "Espandi Sub Serie",
|
"LabelExpandSubSeries": "Espandi Sub Serie",
|
||||||
@@ -350,6 +360,7 @@
|
|||||||
"LabelFontScale": "Dimensione font",
|
"LabelFontScale": "Dimensione font",
|
||||||
"LabelFontStrikethrough": "Barrato",
|
"LabelFontStrikethrough": "Barrato",
|
||||||
"LabelFormat": "Formato",
|
"LabelFormat": "Formato",
|
||||||
|
"LabelFull": "Pieno",
|
||||||
"LabelGenre": "Genere",
|
"LabelGenre": "Genere",
|
||||||
"LabelGenres": "Generi",
|
"LabelGenres": "Generi",
|
||||||
"LabelHardDeleteFile": "Elimina Definitivamente",
|
"LabelHardDeleteFile": "Elimina Definitivamente",
|
||||||
@@ -405,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "Priorità Minima",
|
"LabelLowestPriority": "Priorità Minima",
|
||||||
"LabelMatchExistingUsersBy": "Abbina gli utenti esistenti per",
|
"LabelMatchExistingUsersBy": "Abbina gli utenti esistenti per",
|
||||||
"LabelMatchExistingUsersByDescription": "Utilizzato per connettere gli utenti esistenti. Una volta connessi, gli utenti verranno abbinati a un ID univoco dal tuo provider SSO",
|
"LabelMatchExistingUsersByDescription": "Utilizzato per connettere gli utenti esistenti. Una volta connessi, gli utenti verranno abbinati a un ID univoco dal tuo provider SSO",
|
||||||
|
"LabelMaxEpisodesToDownload": "Max # di episodi da scaricare. Usa 0 per illimitati.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Massimo # di nuovi episodi da scaricare per il controllo",
|
||||||
|
"LabelMaxEpisodesToKeep": "Massimo # di episodi da tenere",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "Il valore 0 non imposta alcun limite massimo. Dopo che un nuovo episodio è stato scaricato automaticamente, questo eliminerà l'episodio più vecchio se hai più di X episodi. Questo eliminerà solo 1 episodio per ogni nuovo download.",
|
||||||
"LabelMediaPlayer": "Media Player",
|
"LabelMediaPlayer": "Media Player",
|
||||||
"LabelMediaType": "Tipo Media",
|
"LabelMediaType": "Tipo Media",
|
||||||
"LabelMetaTag": "Meta Tag",
|
"LabelMetaTag": "Meta Tag",
|
||||||
@@ -450,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Nome dell'attestazione OpenID che contiene un elenco dei gruppi dell'utente. Comunemente indicato come <code>gruppo</code>. <b>se configurato</b>, l'applicazione assegnerà automaticamente i ruoli in base alle appartenenze ai gruppi dell'utente, a condizione che tali gruppi siano denominati \"admin\", \"utente\" o \"ospite\" senza distinzione tra maiuscole e minuscole nell'attestazione. L'attestazione deve contenere un elenco e, se un utente appartiene a più gruppi, l'applicazione assegnerà il ruolo corrispondente al livello di accesso più alto. Se nessun gruppo corrisponde, l'accesso verrà negato.",
|
"LabelOpenIDGroupClaimDescription": "Nome dell'attestazione OpenID che contiene un elenco dei gruppi dell'utente. Comunemente indicato come <code>gruppo</code>. <b>se configurato</b>, l'applicazione assegnerà automaticamente i ruoli in base alle appartenenze ai gruppi dell'utente, a condizione che tali gruppi siano denominati \"admin\", \"utente\" o \"ospite\" senza distinzione tra maiuscole e minuscole nell'attestazione. L'attestazione deve contenere un elenco e, se un utente appartiene a più gruppi, l'applicazione assegnerà il ruolo corrispondente al livello di accesso più alto. Se nessun gruppo corrisponde, l'accesso verrà negato.",
|
||||||
"LabelOpenRSSFeed": "Apri RSS Feed",
|
"LabelOpenRSSFeed": "Apri RSS Feed",
|
||||||
"LabelOverwrite": "Sovrascrivi",
|
"LabelOverwrite": "Sovrascrivi",
|
||||||
|
"LabelPaginationPageXOfY": "Pagina {0} di {1}",
|
||||||
"LabelPassword": "Password",
|
"LabelPassword": "Password",
|
||||||
"LabelPath": "Percorso",
|
"LabelPath": "Percorso",
|
||||||
"LabelPermanent": "Permanente",
|
"LabelPermanent": "Permanente",
|
||||||
"LabelPermissionsAccessAllLibraries": "Può accedere a tutte le librerie",
|
"LabelPermissionsAccessAllLibraries": "Può accedere a tutte le librerie",
|
||||||
"LabelPermissionsAccessAllTags": "Può accedere a tutti i tag",
|
"LabelPermissionsAccessAllTags": "Può accedere a tutti i tag",
|
||||||
"LabelPermissionsAccessExplicitContent": "Può accedere a contenuti espliciti",
|
"LabelPermissionsAccessExplicitContent": "Può accedere a contenuti espliciti",
|
||||||
|
"LabelPermissionsCreateEreader": "Può creare un e-reader",
|
||||||
"LabelPermissionsDelete": "Può Cancellare",
|
"LabelPermissionsDelete": "Può Cancellare",
|
||||||
"LabelPermissionsDownload": "Può Scaricare",
|
"LabelPermissionsDownload": "Può Scaricare",
|
||||||
"LabelPermissionsUpdate": "Può Aggiornare",
|
"LabelPermissionsUpdate": "Può Aggiornare",
|
||||||
@@ -478,7 +495,7 @@
|
|||||||
"LabelProviderAuthorizationValue": "Authorization Header Value",
|
"LabelProviderAuthorizationValue": "Authorization Header Value",
|
||||||
"LabelPubDate": "Data di pubblicazione",
|
"LabelPubDate": "Data di pubblicazione",
|
||||||
"LabelPublishYear": "Anno di pubblicazione",
|
"LabelPublishYear": "Anno di pubblicazione",
|
||||||
"LabelPublishedDate": "{0} pubblicati",
|
"LabelPublishedDate": "Pubblicati {0}",
|
||||||
"LabelPublishedDecade": "Decennio di pubblicazione",
|
"LabelPublishedDecade": "Decennio di pubblicazione",
|
||||||
"LabelPublishedDecades": "Decenni di pubblicazione",
|
"LabelPublishedDecades": "Decenni di pubblicazione",
|
||||||
"LabelPublisher": "Editore",
|
"LabelPublisher": "Editore",
|
||||||
@@ -500,18 +517,24 @@
|
|||||||
"LabelRedo": "Rifai",
|
"LabelRedo": "Rifai",
|
||||||
"LabelRegion": "Regione",
|
"LabelRegion": "Regione",
|
||||||
"LabelReleaseDate": "Data Release",
|
"LabelReleaseDate": "Data Release",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Remuovi tutti i metadata.abs files",
|
||||||
|
"LabelRemoveAllMetadataJson": "Rimuovi tutti i metadata.json files",
|
||||||
"LabelRemoveCover": "Rimuovi cover",
|
"LabelRemoveCover": "Rimuovi cover",
|
||||||
|
"LabelRemoveMetadataFile": "Rimuovi i file metadata nella cartella della libreria",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Rimuovi tutti i file metadata.json e i file metadata.abs nelle tue {0} cartelle.",
|
||||||
"LabelRowsPerPage": "Righe per pagina",
|
"LabelRowsPerPage": "Righe per pagina",
|
||||||
"LabelSearchTerm": "Ricerca",
|
"LabelSearchTerm": "Ricerca",
|
||||||
"LabelSearchTitle": "Cerca Titolo",
|
"LabelSearchTitle": "Cerca Titolo",
|
||||||
"LabelSearchTitleOrASIN": "Cerca titolo o ASIN",
|
"LabelSearchTitleOrASIN": "Cerca titolo o ASIN",
|
||||||
"LabelSeason": "Stagione",
|
"LabelSeason": "Stagione",
|
||||||
|
"LabelSeasonNumber": "Stagione #{0}",
|
||||||
"LabelSelectAll": "Seleziona tutto",
|
"LabelSelectAll": "Seleziona tutto",
|
||||||
"LabelSelectAllEpisodes": "Seleziona tutti gli Episodi",
|
"LabelSelectAllEpisodes": "Seleziona tutti gli Episodi",
|
||||||
"LabelSelectEpisodesShowing": "Selezionati {0} episodi da visualizzare",
|
"LabelSelectEpisodesShowing": "Selezionati {0} episodi da visualizzare",
|
||||||
"LabelSelectUsers": "Selezione Utenti",
|
"LabelSelectUsers": "Selezione Utenti",
|
||||||
"LabelSendEbookToDevice": "Invia il libro a...",
|
"LabelSendEbookToDevice": "Invia il libro a...",
|
||||||
"LabelSequence": "Sequenza",
|
"LabelSequence": "Sequenza",
|
||||||
|
"LabelSerial": "Seriale",
|
||||||
"LabelSeries": "Serie",
|
"LabelSeries": "Serie",
|
||||||
"LabelSeriesName": "Nome Serie",
|
"LabelSeriesName": "Nome Serie",
|
||||||
"LabelSeriesProgress": "Cominciato",
|
"LabelSeriesProgress": "Cominciato",
|
||||||
@@ -540,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Le serie che hanno un solo libro saranno nascoste dalla pagina della serie e dagli scaffali della home page.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Le serie che hanno un solo libro saranno nascoste dalla pagina della serie e dagli scaffali della home page.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Home page con sfondo legno",
|
"LabelSettingsHomePageBookshelfView": "Home page con sfondo legno",
|
||||||
"LabelSettingsLibraryBookshelfView": "Libreria con sfondo legno",
|
"LabelSettingsLibraryBookshelfView": "Libreria con sfondo legno",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "La percentuale di completamento è maggiore di",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Il tempo rimanente è inferiore a (secondi)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Contrassegna l'elemento multimediale come terminato quando",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Salta i libri precedenti nella serie Continua",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Salta i libri precedenti nella serie Continua",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Lo scaffale della home page Continua serie mostra il primo libro non iniziato della serie che ha almeno un libro finito e nessun libro in corso. Abilitando questa impostazione le serie continueranno dal libro completato più lontano invece che dal primo libro non iniziato.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Lo scaffale della home page Continua serie mostra il primo libro non iniziato della serie che ha almeno un libro finito e nessun libro in corso. Abilitando questa impostazione le serie continueranno dal libro completato più lontano invece che dal primo libro non iniziato.",
|
||||||
"LabelSettingsParseSubtitles": "Analizza sottotitoli",
|
"LabelSettingsParseSubtitles": "Analizza sottotitoli",
|
||||||
@@ -604,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} minuti",
|
"LabelTimeDurationXMinutes": "{0} minuti",
|
||||||
"LabelTimeDurationXSeconds": "{0} secondi",
|
"LabelTimeDurationXSeconds": "{0} secondi",
|
||||||
"LabelTimeInMinutes": "Tempo in minuti",
|
"LabelTimeInMinutes": "Tempo in minuti",
|
||||||
|
"LabelTimeLeft": "{0} sinistra",
|
||||||
"LabelTimeListened": "Tempo di Ascolto",
|
"LabelTimeListened": "Tempo di Ascolto",
|
||||||
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
||||||
"LabelTimeRemaining": "{0} rimanente",
|
"LabelTimeRemaining": "{0} rimanente",
|
||||||
@@ -624,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "Multi-traccia",
|
"LabelTracksMultiTrack": "Multi-traccia",
|
||||||
"LabelTracksNone": "Nessuna traccia",
|
"LabelTracksNone": "Nessuna traccia",
|
||||||
"LabelTracksSingleTrack": "Traccia-singola",
|
"LabelTracksSingleTrack": "Traccia-singola",
|
||||||
|
"LabelTrailer": "Trailer",
|
||||||
"LabelType": "Tipo",
|
"LabelType": "Tipo",
|
||||||
"LabelUnabridged": "Integrale",
|
"LabelUnabridged": "Integrale",
|
||||||
"LabelUndo": "Annulla",
|
"LabelUndo": "Annulla",
|
||||||
@@ -640,6 +668,7 @@
|
|||||||
"LabelUseAdvancedOptions": "Usa le opzioni avanzate",
|
"LabelUseAdvancedOptions": "Usa le opzioni avanzate",
|
||||||
"LabelUseChapterTrack": "Usa il Capitolo della Traccia",
|
"LabelUseChapterTrack": "Usa il Capitolo della Traccia",
|
||||||
"LabelUseFullTrack": "Usa la traccia totale",
|
"LabelUseFullTrack": "Usa la traccia totale",
|
||||||
|
"LabelUseZeroForUnlimited": "Usa 0 per illimitato",
|
||||||
"LabelUser": "Utente",
|
"LabelUser": "Utente",
|
||||||
"LabelUsername": "Nome utente",
|
"LabelUsername": "Nome utente",
|
||||||
"LabelValue": "Valore",
|
"LabelValue": "Valore",
|
||||||
@@ -653,7 +682,7 @@
|
|||||||
"LabelXBooks": "{0} libri",
|
"LabelXBooks": "{0} libri",
|
||||||
"LabelXItems": "{0} oggetti",
|
"LabelXItems": "{0} oggetti",
|
||||||
"LabelYearReviewHide": "Nascondi Anno in rassegna",
|
"LabelYearReviewHide": "Nascondi Anno in rassegna",
|
||||||
"LabelYearReviewShow": "Vedi Anno in rassegna",
|
"LabelYearReviewShow": "Mostra Anno in rassegna",
|
||||||
"LabelYourAudiobookDuration": "La durata dell'audiolibro",
|
"LabelYourAudiobookDuration": "La durata dell'audiolibro",
|
||||||
"LabelYourBookmarks": "I tuoi preferiti",
|
"LabelYourBookmarks": "I tuoi preferiti",
|
||||||
"LabelYourPlaylists": "le tue Playlist",
|
"LabelYourPlaylists": "le tue Playlist",
|
||||||
@@ -698,6 +727,7 @@
|
|||||||
"MessageConfirmPurgeCache": "L'eliminazione della cache eliminerà l'intera directory dei <code>/metadata/cache</code>. <br /><br />Sei sicuro di voler rimuovere la directory della cache?",
|
"MessageConfirmPurgeCache": "L'eliminazione della cache eliminerà l'intera directory dei <code>/metadata/cache</code>. <br /><br />Sei sicuro di voler rimuovere la directory della cache?",
|
||||||
"MessageConfirmPurgeItemsCache": "L'eliminazione della cache degli elementi eliminerà l'intera directory <code>/metadata/cache/oggetti</code>.<br />Sei sicuro?",
|
"MessageConfirmPurgeItemsCache": "L'eliminazione della cache degli elementi eliminerà l'intera directory <code>/metadata/cache/oggetti</code>.<br />Sei sicuro?",
|
||||||
"MessageConfirmQuickEmbed": "Attenzione! L'incorporamento rapido non eseguirà il backup dei file audio. Assicurati di avere un backup dei tuoi file audio. <br><br>Vuoi Continuare?",
|
"MessageConfirmQuickEmbed": "Attenzione! L'incorporamento rapido non eseguirà il backup dei file audio. Assicurati di avere un backup dei tuoi file audio. <br><br>Vuoi Continuare?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "Gli episodi di corrispondenza rapida sovrascriveranno i dettagli se viene trovata una corrispondenza. Saranno aggiornati solo gli episodi non corrispondenti. Sei sicuro?",
|
||||||
"MessageConfirmReScanLibraryItems": "Sei sicuro di voler ripetere la scansione? {0} oggetti?",
|
"MessageConfirmReScanLibraryItems": "Sei sicuro di voler ripetere la scansione? {0} oggetti?",
|
||||||
"MessageConfirmRemoveAllChapters": "Sei sicuro di voler rimuovere tutti i capitoli?",
|
"MessageConfirmRemoveAllChapters": "Sei sicuro di voler rimuovere tutti i capitoli?",
|
||||||
"MessageConfirmRemoveAuthor": "Sei sicuro di voler rimuovere l'autore? \"{0}\"?",
|
"MessageConfirmRemoveAuthor": "Sei sicuro di voler rimuovere l'autore? \"{0}\"?",
|
||||||
@@ -705,6 +735,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "Sei sicuro di voler rimuovere l'episodio \"{0}\"?",
|
"MessageConfirmRemoveEpisode": "Sei sicuro di voler rimuovere l'episodio \"{0}\"?",
|
||||||
"MessageConfirmRemoveEpisodes": "Sei sicuro di voler rimuovere {0} episodi?",
|
"MessageConfirmRemoveEpisodes": "Sei sicuro di voler rimuovere {0} episodi?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Sei sicuro di voler rimuovere {0} sessioni di Ascolto?",
|
"MessageConfirmRemoveListeningSessions": "Sei sicuro di voler rimuovere {0} sessioni di Ascolto?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Vuoi davvero rimuovere tutti i metadati.{0} file nelle cartelle degli elementi della tua libreria?",
|
||||||
"MessageConfirmRemoveNarrator": "Sei sicuro di voler rimuovere il narratore \"{0}\"?",
|
"MessageConfirmRemoveNarrator": "Sei sicuro di voler rimuovere il narratore \"{0}\"?",
|
||||||
"MessageConfirmRemovePlaylist": "Sei sicuro di voler rimuovere la tua playlist \"{0}\"?",
|
"MessageConfirmRemovePlaylist": "Sei sicuro di voler rimuovere la tua playlist \"{0}\"?",
|
||||||
"MessageConfirmRenameGenre": "Sei sicuro di voler rinominare il genere \"{0}\" in \"{1}\" per tutti gli oggetti?",
|
"MessageConfirmRenameGenre": "Sei sicuro di voler rinominare il genere \"{0}\" in \"{1}\" per tutti gli oggetti?",
|
||||||
@@ -748,7 +779,7 @@
|
|||||||
"MessageNoBackups": "Nessun Backup",
|
"MessageNoBackups": "Nessun Backup",
|
||||||
"MessageNoBookmarks": "Nessun preferito",
|
"MessageNoBookmarks": "Nessun preferito",
|
||||||
"MessageNoChapters": "Nessun capitolo",
|
"MessageNoChapters": "Nessun capitolo",
|
||||||
"MessageNoCollections": "Nessuna Raccolta",
|
"MessageNoCollections": "Nessuna Collezione",
|
||||||
"MessageNoCoversFound": "Nessuna Cover Trovata",
|
"MessageNoCoversFound": "Nessuna Cover Trovata",
|
||||||
"MessageNoDescription": "Nessuna descrizione",
|
"MessageNoDescription": "Nessuna descrizione",
|
||||||
"MessageNoDevices": "nessun dispositivo",
|
"MessageNoDevices": "nessun dispositivo",
|
||||||
@@ -785,6 +816,7 @@
|
|||||||
"MessagePodcastSearchField": "Inserisci il termine di ricerca o l'URL del feed RSS",
|
"MessagePodcastSearchField": "Inserisci il termine di ricerca o l'URL del feed RSS",
|
||||||
"MessageQuickEmbedInProgress": "Incorporamento rapido in corso",
|
"MessageQuickEmbedInProgress": "Incorporamento rapido in corso",
|
||||||
"MessageQuickEmbedQueue": "In coda per incorporamento rapido ({0} in coda)",
|
"MessageQuickEmbedQueue": "In coda per incorporamento rapido ({0} in coda)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Associamento veloce di Tutti gli episodi",
|
||||||
"MessageQuickMatchDescription": "Compila i dettagli dell'articolo vuoto e copri con il risultato della prima corrispondenza di '{0}'. Non sovrascrive i dettagli a meno che non sia abilitata l'impostazione del server \"Preferisci metadati corrispondenti\".",
|
"MessageQuickMatchDescription": "Compila i dettagli dell'articolo vuoto e copri con il risultato della prima corrispondenza di '{0}'. Non sovrascrive i dettagli a meno che non sia abilitata l'impostazione del server \"Preferisci metadati corrispondenti\".",
|
||||||
"MessageRemoveChapter": "Rimuovi Capitolo",
|
"MessageRemoveChapter": "Rimuovi Capitolo",
|
||||||
"MessageRemoveEpisodes": "rimuovi {0} episodio(i)",
|
"MessageRemoveEpisodes": "rimuovi {0} episodio(i)",
|
||||||
@@ -883,6 +915,7 @@
|
|||||||
"StatsYearInReview": "ANNO IN RASSEGNA",
|
"StatsYearInReview": "ANNO IN RASSEGNA",
|
||||||
"ToastAccountUpdateSuccess": "Account Aggiornato",
|
"ToastAccountUpdateSuccess": "Account Aggiornato",
|
||||||
"ToastAppriseUrlRequired": "È necessario immettere un indirizzo Apprise",
|
"ToastAppriseUrlRequired": "È necessario immettere un indirizzo Apprise",
|
||||||
|
"ToastAsinRequired": "L'ASIN è obbligatorio",
|
||||||
"ToastAuthorImageRemoveSuccess": "Immagine Autore Rimossa",
|
"ToastAuthorImageRemoveSuccess": "Immagine Autore Rimossa",
|
||||||
"ToastAuthorNotFound": "Autore\"{0}\" non trovato",
|
"ToastAuthorNotFound": "Autore\"{0}\" non trovato",
|
||||||
"ToastAuthorRemoveSuccess": "Autore rimosso",
|
"ToastAuthorRemoveSuccess": "Autore rimosso",
|
||||||
@@ -902,6 +935,8 @@
|
|||||||
"ToastBackupUploadSuccess": "Backup caricato",
|
"ToastBackupUploadSuccess": "Backup caricato",
|
||||||
"ToastBatchDeleteFailed": "Eliminazione batch non riuscita",
|
"ToastBatchDeleteFailed": "Eliminazione batch non riuscita",
|
||||||
"ToastBatchDeleteSuccess": "Eliminazione batch riuscita",
|
"ToastBatchDeleteSuccess": "Eliminazione batch riuscita",
|
||||||
|
"ToastBatchQuickMatchFailed": "Batch Quick Match non riuscito!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Avviata la ricerca rapida in batch di {0} libri!",
|
||||||
"ToastBatchUpdateFailed": "Batch di aggiornamento fallito",
|
"ToastBatchUpdateFailed": "Batch di aggiornamento fallito",
|
||||||
"ToastBatchUpdateSuccess": "Batch di aggiornamento finito",
|
"ToastBatchUpdateSuccess": "Batch di aggiornamento finito",
|
||||||
"ToastBookmarkCreateFailed": "Creazione segnalibro fallita",
|
"ToastBookmarkCreateFailed": "Creazione segnalibro fallita",
|
||||||
@@ -913,6 +948,7 @@
|
|||||||
"ToastChaptersHaveErrors": "I capitoli contengono errori",
|
"ToastChaptersHaveErrors": "I capitoli contengono errori",
|
||||||
"ToastChaptersMustHaveTitles": "I capitoli devono avere titoli",
|
"ToastChaptersMustHaveTitles": "I capitoli devono avere titoli",
|
||||||
"ToastChaptersRemoved": "Capitoli rimossi",
|
"ToastChaptersRemoved": "Capitoli rimossi",
|
||||||
|
"ToastChaptersUpdated": "Capitoli aggiornati",
|
||||||
"ToastCollectionItemsAddFailed": "l'aggiunta dell'elemento(i) alla raccolta non è riuscito",
|
"ToastCollectionItemsAddFailed": "l'aggiunta dell'elemento(i) alla raccolta non è riuscito",
|
||||||
"ToastCollectionItemsAddSuccess": "L'aggiunta dell'elemento(i) alla raccolta è riuscito",
|
"ToastCollectionItemsAddSuccess": "L'aggiunta dell'elemento(i) alla raccolta è riuscito",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Oggetto(i) rimossi dalla Raccolta",
|
"ToastCollectionItemsRemoveSuccess": "Oggetto(i) rimossi dalla Raccolta",
|
||||||
@@ -930,11 +966,14 @@
|
|||||||
"ToastEncodeCancelSucces": "Codifica annullata",
|
"ToastEncodeCancelSucces": "Codifica annullata",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "Impossibile cancellare la coda",
|
"ToastEpisodeDownloadQueueClearFailed": "Impossibile cancellare la coda",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "Coda di download degli episodi cancellata",
|
"ToastEpisodeDownloadQueueClearSuccess": "Coda di download degli episodi cancellata",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} episodi aggiornati",
|
||||||
"ToastErrorCannotShare": "Impossibile condividere in modo nativo su questo dispositivo",
|
"ToastErrorCannotShare": "Impossibile condividere in modo nativo su questo dispositivo",
|
||||||
"ToastFailedToLoadData": "Impossibile caricare i dati",
|
"ToastFailedToLoadData": "Impossibile caricare i dati",
|
||||||
|
"ToastFailedToMatch": "Impossibile abbinare",
|
||||||
"ToastFailedToShare": "Impossibile condividere",
|
"ToastFailedToShare": "Impossibile condividere",
|
||||||
"ToastFailedToUpdate": "Non aggiornato",
|
"ToastFailedToUpdate": "Non aggiornato",
|
||||||
"ToastInvalidImageUrl": "URL dell'immagine non valido",
|
"ToastInvalidImageUrl": "URL dell'immagine non valido",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Numero massimo di episodi non valido da scaricare",
|
||||||
"ToastInvalidUrl": "URL non valido",
|
"ToastInvalidUrl": "URL non valido",
|
||||||
"ToastItemCoverUpdateSuccess": "Cover aggiornata",
|
"ToastItemCoverUpdateSuccess": "Cover aggiornata",
|
||||||
"ToastItemDeletedFailed": "Impossibile eliminare l'elemento",
|
"ToastItemDeletedFailed": "Impossibile eliminare l'elemento",
|
||||||
@@ -953,14 +992,21 @@
|
|||||||
"ToastLibraryScanStarted": "Scansione Libreria iniziata",
|
"ToastLibraryScanStarted": "Scansione Libreria iniziata",
|
||||||
"ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata",
|
"ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata",
|
||||||
"ToastMatchAllAuthorsFailed": "Tutti gli autori non sono potuti essere classificati",
|
"ToastMatchAllAuthorsFailed": "Tutti gli autori non sono potuti essere classificati",
|
||||||
|
"ToastMetadataFilesRemovedError": "Errore durante la rimozione dei metadati. {0} file",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "Nessun metadato. {0} file trovati nella libreria",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Nessun metadato. {0} file rimossi",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadati.{1} file rimossi",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Deve avere almeno un percorso",
|
||||||
"ToastNameEmailRequired": "Nome ed email sono obbligatori",
|
"ToastNameEmailRequired": "Nome ed email sono obbligatori",
|
||||||
"ToastNameRequired": "Il nome è obbligatorio",
|
"ToastNameRequired": "Il nome è obbligatorio",
|
||||||
|
"ToastNewEpisodesFound": "{0} nuovi episodi trovati",
|
||||||
"ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"",
|
"ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"",
|
||||||
"ToastNewUserCreatedSuccess": "Nuovo account creato",
|
"ToastNewUserCreatedSuccess": "Nuovo account creato",
|
||||||
"ToastNewUserLibraryError": "È necessario selezionare almeno una libreria",
|
"ToastNewUserLibraryError": "È necessario selezionare almeno una libreria",
|
||||||
"ToastNewUserPasswordError": "Deve avere una password, solo l'utente root può avere una password vuota",
|
"ToastNewUserPasswordError": "Deve avere una password, solo l'utente root può avere una password vuota",
|
||||||
"ToastNewUserTagError": "Devi selezionare almeno un tag",
|
"ToastNewUserTagError": "Devi selezionare almeno un tag",
|
||||||
"ToastNewUserUsernameError": "Inserisci un nome utente",
|
"ToastNewUserUsernameError": "Inserisci un nome utente",
|
||||||
|
"ToastNoNewEpisodesFound": "Nessun nuovo episodio trovato",
|
||||||
"ToastNoUpdatesNecessary": "Nessun aggiornamento necessario",
|
"ToastNoUpdatesNecessary": "Nessun aggiornamento necessario",
|
||||||
"ToastNotificationCreateFailed": "Impossibile creare la notifica",
|
"ToastNotificationCreateFailed": "Impossibile creare la notifica",
|
||||||
"ToastNotificationDeleteFailed": "Impossibile eliminare la notifica",
|
"ToastNotificationDeleteFailed": "Impossibile eliminare la notifica",
|
||||||
@@ -979,6 +1025,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "Impossibile ottenere il feed del podcast",
|
"ToastPodcastGetFeedFailed": "Impossibile ottenere il feed del podcast",
|
||||||
"ToastPodcastNoEpisodesInFeed": "Nessun episodio trovato nel feed RSS",
|
"ToastPodcastNoEpisodesInFeed": "Nessun episodio trovato nel feed RSS",
|
||||||
"ToastPodcastNoRssFeed": "Il podcast non ha un feed RSS",
|
"ToastPodcastNoRssFeed": "Il podcast non ha un feed RSS",
|
||||||
|
"ToastProgressIsNotBeingSynced": "L'avanzamento non è sincronizzato, riavviare la riproduzione",
|
||||||
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
|
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
|
||||||
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
|
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
|
||||||
"ToastProviderNameAndUrlRequired": "Nome e URL richiesti",
|
"ToastProviderNameAndUrlRequired": "Nome e URL richiesti",
|
||||||
@@ -1005,6 +1052,7 @@
|
|||||||
"ToastSessionCloseFailed": "Disconnessione Fallita",
|
"ToastSessionCloseFailed": "Disconnessione Fallita",
|
||||||
"ToastSessionDeleteFailed": "Errore eliminazione sessione",
|
"ToastSessionDeleteFailed": "Errore eliminazione sessione",
|
||||||
"ToastSessionDeleteSuccess": "Sessione cancellata",
|
"ToastSessionDeleteSuccess": "Sessione cancellata",
|
||||||
|
"ToastSleepTimerDone": "Timer di spegnimento eseguito... zZzzZz",
|
||||||
"ToastSlugMustChange": "Lo slug contiene caratteri non validi",
|
"ToastSlugMustChange": "Lo slug contiene caratteri non validi",
|
||||||
"ToastSlugRequired": "È richiesto lo slug",
|
"ToastSlugRequired": "È richiesto lo slug",
|
||||||
"ToastSocketConnected": "Socket connesso",
|
"ToastSocketConnected": "Socket connesso",
|
||||||
|
|||||||
+364
-2
@@ -30,6 +30,8 @@
|
|||||||
"ButtonEditChapters": "Hoofdstukken wijzigen",
|
"ButtonEditChapters": "Hoofdstukken wijzigen",
|
||||||
"ButtonEditPodcast": "Podcast wijzigen",
|
"ButtonEditPodcast": "Podcast wijzigen",
|
||||||
"ButtonEnable": "Aanzetten",
|
"ButtonEnable": "Aanzetten",
|
||||||
|
"ButtonFireAndFail": "Fire and Fail",
|
||||||
|
"ButtonFireOnTest": "Fire onTest event",
|
||||||
"ButtonForceReScan": "Forceer nieuwe scan",
|
"ButtonForceReScan": "Forceer nieuwe scan",
|
||||||
"ButtonFullPath": "Volledig pad",
|
"ButtonFullPath": "Volledig pad",
|
||||||
"ButtonHide": "Verberg",
|
"ButtonHide": "Verberg",
|
||||||
@@ -65,6 +67,7 @@
|
|||||||
"ButtonQueueAddItem": "In wachtrij zetten",
|
"ButtonQueueAddItem": "In wachtrij zetten",
|
||||||
"ButtonQueueRemoveItem": "Uit wachtrij verwijderen",
|
"ButtonQueueRemoveItem": "Uit wachtrij verwijderen",
|
||||||
"ButtonQuickEmbed": "Snel Embedden",
|
"ButtonQuickEmbed": "Snel Embedden",
|
||||||
|
"ButtonQuickEmbedMetadata": "Snel Metadata Insluiten",
|
||||||
"ButtonQuickMatch": "Snelle match",
|
"ButtonQuickMatch": "Snelle match",
|
||||||
"ButtonReScan": "Nieuwe scan",
|
"ButtonReScan": "Nieuwe scan",
|
||||||
"ButtonRead": "Lees",
|
"ButtonRead": "Lees",
|
||||||
@@ -97,6 +100,8 @@
|
|||||||
"ButtonStats": "Statistieken",
|
"ButtonStats": "Statistieken",
|
||||||
"ButtonSubmit": "Indienen",
|
"ButtonSubmit": "Indienen",
|
||||||
"ButtonTest": "Testen",
|
"ButtonTest": "Testen",
|
||||||
|
"ButtonUnlinkOpenId": "OpenID Ontkoppelen",
|
||||||
|
"ButtonUpload": "Upload",
|
||||||
"ButtonUploadBackup": "Upload back-up",
|
"ButtonUploadBackup": "Upload back-up",
|
||||||
"ButtonUploadCover": "Upload cover",
|
"ButtonUploadCover": "Upload cover",
|
||||||
"ButtonUploadOPMLFile": "Upload OPML-bestand",
|
"ButtonUploadOPMLFile": "Upload OPML-bestand",
|
||||||
@@ -108,10 +113,12 @@
|
|||||||
"ErrorUploadFetchMetadataNoResults": "Kan metadata niet ophalen - probeer de titel en/of auteur te updaten",
|
"ErrorUploadFetchMetadataNoResults": "Kan metadata niet ophalen - probeer de titel en/of auteur te updaten",
|
||||||
"ErrorUploadLacksTitle": "Moet een titel hebben",
|
"ErrorUploadLacksTitle": "Moet een titel hebben",
|
||||||
"HeaderAccount": "Account",
|
"HeaderAccount": "Account",
|
||||||
|
"HeaderAddCustomMetadataProvider": "Aangepaste Metadataprovider Toevoegen",
|
||||||
"HeaderAdvanced": "Geavanceerd",
|
"HeaderAdvanced": "Geavanceerd",
|
||||||
"HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen",
|
"HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen",
|
||||||
"HeaderAudioTracks": "Audiotracks",
|
"HeaderAudioTracks": "Audiotracks",
|
||||||
"HeaderAudiobookTools": "Audioboekbestandbeheer tools",
|
"HeaderAudiobookTools": "Audioboekbestandbeheer tools",
|
||||||
|
"HeaderAuthentication": "Authenticatie",
|
||||||
"HeaderBackups": "Back-ups",
|
"HeaderBackups": "Back-ups",
|
||||||
"HeaderChangePassword": "Wachtwoord wijzigen",
|
"HeaderChangePassword": "Wachtwoord wijzigen",
|
||||||
"HeaderChapters": "Hoofdstukken",
|
"HeaderChapters": "Hoofdstukken",
|
||||||
@@ -120,6 +127,8 @@
|
|||||||
"HeaderCollectionItems": "Collectie-objecten",
|
"HeaderCollectionItems": "Collectie-objecten",
|
||||||
"HeaderCover": "Omslag",
|
"HeaderCover": "Omslag",
|
||||||
"HeaderCurrentDownloads": "Huidige downloads",
|
"HeaderCurrentDownloads": "Huidige downloads",
|
||||||
|
"HeaderCustomMessageOnLogin": "Aangepast Bericht bij Aanmelden",
|
||||||
|
"HeaderCustomMetadataProviders": "Aangepaste Metadata Providers",
|
||||||
"HeaderDetails": "Details",
|
"HeaderDetails": "Details",
|
||||||
"HeaderDownloadQueue": "Download-wachtrij",
|
"HeaderDownloadQueue": "Download-wachtrij",
|
||||||
"HeaderEbookFiles": "Ebook bestanden",
|
"HeaderEbookFiles": "Ebook bestanden",
|
||||||
@@ -140,16 +149,27 @@
|
|||||||
"HeaderLibraryStats": "Bibliotheekstatistieken",
|
"HeaderLibraryStats": "Bibliotheekstatistieken",
|
||||||
"HeaderListeningSessions": "Luistersessies",
|
"HeaderListeningSessions": "Luistersessies",
|
||||||
"HeaderListeningStats": "Luisterstatistieken",
|
"HeaderListeningStats": "Luisterstatistieken",
|
||||||
|
"HeaderLogin": "Aanmelden",
|
||||||
|
"HeaderLogs": "Logboek",
|
||||||
"HeaderManageGenres": "Genres beheren",
|
"HeaderManageGenres": "Genres beheren",
|
||||||
"HeaderManageTags": "Tags beheren",
|
"HeaderManageTags": "Tags beheren",
|
||||||
|
"HeaderMapDetails": "Map details",
|
||||||
|
"HeaderMatch": "Vergelijken",
|
||||||
|
"HeaderMetadataOrderOfPrecedence": "Metadata volgorde",
|
||||||
"HeaderMetadataToEmbed": "In te sluiten metadata",
|
"HeaderMetadataToEmbed": "In te sluiten metadata",
|
||||||
"HeaderNewAccount": "Nieuwe account",
|
"HeaderNewAccount": "Nieuwe account",
|
||||||
"HeaderNewLibrary": "Nieuwe bibliotheek",
|
"HeaderNewLibrary": "Nieuwe bibliotheek",
|
||||||
|
"HeaderNotificationCreate": "Notificatie Aanmaken",
|
||||||
|
"HeaderNotificationUpdate": "Update Notificatie",
|
||||||
"HeaderNotifications": "Notificaties",
|
"HeaderNotifications": "Notificaties",
|
||||||
|
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authenticatie",
|
||||||
|
"HeaderOpenListeningSessions": "Open Luistersessies",
|
||||||
"HeaderOpenRSSFeed": "Open RSS-feed",
|
"HeaderOpenRSSFeed": "Open RSS-feed",
|
||||||
"HeaderOtherFiles": "Andere bestanden",
|
"HeaderOtherFiles": "Andere bestanden",
|
||||||
|
"HeaderPasswordAuthentication": "Wachtwoord Authenticatie",
|
||||||
"HeaderPermissions": "Toestemmingen",
|
"HeaderPermissions": "Toestemmingen",
|
||||||
"HeaderPlayerQueue": "Afspeelwachtrij",
|
"HeaderPlayerQueue": "Afspeelwachtrij",
|
||||||
|
"HeaderPlayerSettings": "Speler Instellingen",
|
||||||
"HeaderPlaylist": "Afspeellijst",
|
"HeaderPlaylist": "Afspeellijst",
|
||||||
"HeaderPlaylistItems": "Onderdelen in afspeellijst",
|
"HeaderPlaylistItems": "Onderdelen in afspeellijst",
|
||||||
"HeaderPodcastsToAdd": "Toe te voegen podcasts",
|
"HeaderPodcastsToAdd": "Toe te voegen podcasts",
|
||||||
@@ -161,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Verwijder {0} afleveringen",
|
"HeaderRemoveEpisodes": "Verwijder {0} afleveringen",
|
||||||
"HeaderSavedMediaProgress": "Opgeslagen mediavoortgang",
|
"HeaderSavedMediaProgress": "Opgeslagen mediavoortgang",
|
||||||
"HeaderSchedule": "Schema",
|
"HeaderSchedule": "Schema",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Automatische afleveringsdownloads plannen",
|
||||||
"HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans",
|
"HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans",
|
||||||
"HeaderSession": "Sessie",
|
"HeaderSession": "Sessie",
|
||||||
"HeaderSetBackupSchedule": "Kies schema voor back-up",
|
"HeaderSetBackupSchedule": "Kies schema voor back-up",
|
||||||
@@ -168,6 +189,7 @@
|
|||||||
"HeaderSettingsDisplay": "Toon",
|
"HeaderSettingsDisplay": "Toon",
|
||||||
"HeaderSettingsExperimental": "Experimentele functies",
|
"HeaderSettingsExperimental": "Experimentele functies",
|
||||||
"HeaderSettingsGeneral": "Algemeen",
|
"HeaderSettingsGeneral": "Algemeen",
|
||||||
|
"HeaderSettingsScanner": "Scanner",
|
||||||
"HeaderSleepTimer": "Slaaptimer",
|
"HeaderSleepTimer": "Slaaptimer",
|
||||||
"HeaderStatsLargestItems": "Grootste items",
|
"HeaderStatsLargestItems": "Grootste items",
|
||||||
"HeaderStatsLongestItems": "Langste items (uren)",
|
"HeaderStatsLongestItems": "Langste items (uren)",
|
||||||
@@ -176,13 +198,18 @@
|
|||||||
"HeaderStatsTop10Authors": "Top 10 auteurs",
|
"HeaderStatsTop10Authors": "Top 10 auteurs",
|
||||||
"HeaderStatsTop5Genres": "Top 5 genres",
|
"HeaderStatsTop5Genres": "Top 5 genres",
|
||||||
"HeaderTableOfContents": "Inhoudsopgave",
|
"HeaderTableOfContents": "Inhoudsopgave",
|
||||||
|
"HeaderTools": "Gereedschap",
|
||||||
"HeaderUpdateAccount": "Account bijwerken",
|
"HeaderUpdateAccount": "Account bijwerken",
|
||||||
"HeaderUpdateAuthor": "Auteur bijwerken",
|
"HeaderUpdateAuthor": "Auteur bijwerken",
|
||||||
"HeaderUpdateDetails": "Details bijwerken",
|
"HeaderUpdateDetails": "Details bijwerken",
|
||||||
"HeaderUpdateLibrary": "Bibliotheek bijwerken",
|
"HeaderUpdateLibrary": "Bibliotheek bijwerken",
|
||||||
"HeaderUsers": "Gebruikers",
|
"HeaderUsers": "Gebruikers",
|
||||||
|
"HeaderYearReview": "Jaar {0} in Review",
|
||||||
"HeaderYourStats": "Je statistieken",
|
"HeaderYourStats": "Je statistieken",
|
||||||
"LabelAbridged": "Verkort",
|
"LabelAbridged": "Verkort",
|
||||||
|
"LabelAbridgedChecked": "Verkort (gechecked)",
|
||||||
|
"LabelAbridgedUnchecked": "Onverkort (niet gechecked)",
|
||||||
|
"LabelAccessibleBy": "Toegankelijk door",
|
||||||
"LabelAccountType": "Accounttype",
|
"LabelAccountType": "Accounttype",
|
||||||
"LabelAccountTypeAdmin": "Beheerder",
|
"LabelAccountTypeAdmin": "Beheerder",
|
||||||
"LabelAccountTypeGuest": "Gast",
|
"LabelAccountTypeGuest": "Gast",
|
||||||
@@ -193,32 +220,55 @@
|
|||||||
"LabelAddToPlaylist": "Toevoegen aan afspeellijst",
|
"LabelAddToPlaylist": "Toevoegen aan afspeellijst",
|
||||||
"LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst",
|
"LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst",
|
||||||
"LabelAddedAt": "Toegevoegd op",
|
"LabelAddedAt": "Toegevoegd op",
|
||||||
|
"LabelAddedDate": "Toegevoegd {0}",
|
||||||
|
"LabelAdminUsersOnly": "Enkel Admin gebruikers",
|
||||||
"LabelAll": "Alle",
|
"LabelAll": "Alle",
|
||||||
"LabelAllUsers": "Alle gebruikers",
|
"LabelAllUsers": "Alle gebruikers",
|
||||||
|
"LabelAllUsersExcludingGuests": "Alle gebruikers exclusief gasten",
|
||||||
|
"LabelAllUsersIncludingGuests": "Alle gebruikers inclusief gasten",
|
||||||
"LabelAlreadyInYourLibrary": "Reeds in je bibliotheek",
|
"LabelAlreadyInYourLibrary": "Reeds in je bibliotheek",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Achteraan toevoegen",
|
"LabelAppend": "Achteraan toevoegen",
|
||||||
|
"LabelAudioBitrate": "Audio Bitrate (b.v. 128k)",
|
||||||
|
"LabelAudioChannels": "Audio Kanalen (1 of 2)",
|
||||||
|
"LabelAudioCodec": "Audio Codec",
|
||||||
"LabelAuthor": "Auteur",
|
"LabelAuthor": "Auteur",
|
||||||
"LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)",
|
"LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)",
|
||||||
"LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)",
|
"LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)",
|
||||||
"LabelAuthors": "Auteurs",
|
"LabelAuthors": "Auteurs",
|
||||||
"LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden",
|
"LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden",
|
||||||
|
"LabelAutoFetchMetadata": "Automatisch Metadata Ophalen",
|
||||||
|
"LabelAutoFetchMetadataHelp": "Haalt metadata op voor titel, auteur en serie om het uploaden te stroomlijnen. Aanvullende metadata moet mogelijk worden gematcht na het uploaden.",
|
||||||
|
"LabelAutoLaunch": "Automatisch Openen",
|
||||||
|
"LabelAutoLaunchDescription": "Automatisch doorverwijzen naar de auth-provider bij het navigeren naar de inlogpagina (handmatig pad <code>/login?autoLaunch=0</code>)",
|
||||||
|
"LabelAutoRegister": "Automatisch Registreren",
|
||||||
|
"LabelAutoRegisterDescription": "Automatisch nieuwe gebruikers aanmaken na inloggen",
|
||||||
"LabelBackToUser": "Terug naar gebruiker",
|
"LabelBackToUser": "Terug naar gebruiker",
|
||||||
|
"LabelBackupAudioFiles": "Back-up audiobestanden",
|
||||||
"LabelBackupLocation": "Back-up locatie",
|
"LabelBackupLocation": "Back-up locatie",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen",
|
"LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups",
|
||||||
"LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB)",
|
"LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB) (0 voor ongelimiteerd)",
|
||||||
"LabelBackupsMaxBackupSizeHelp": "Als een beveiliging tegen verkeerde instelling, zullen back-up mislukken als ze de ingestelde grootte overschrijden.",
|
"LabelBackupsMaxBackupSizeHelp": "Als een beveiliging tegen verkeerde instelling, zullen back-up mislukken als ze de ingestelde grootte overschrijden.",
|
||||||
"LabelBackupsNumberToKeep": "Aantal te bewaren back-ups",
|
"LabelBackupsNumberToKeep": "Aantal te bewaren back-ups",
|
||||||
"LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.",
|
"LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.",
|
||||||
|
"LabelBitrate": "Bitrate",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Boeken",
|
"LabelBooks": "Boeken",
|
||||||
|
"LabelButtonText": "Knop Tekst",
|
||||||
|
"LabelByAuthor": "Door {0}",
|
||||||
"LabelChangePassword": "Wachtwoord wijzigen",
|
"LabelChangePassword": "Wachtwoord wijzigen",
|
||||||
"LabelChannels": "Kanalen",
|
"LabelChannels": "Kanalen",
|
||||||
|
"LabelChapterCount": "{0} Hoofdstukken",
|
||||||
"LabelChapterTitle": "Hoofdstuktitel",
|
"LabelChapterTitle": "Hoofdstuktitel",
|
||||||
"LabelChapters": "Hoofdstukken",
|
"LabelChapters": "Hoofdstukken",
|
||||||
"LabelChaptersFound": "Hoofdstukken gevonden",
|
"LabelChaptersFound": "Hoofdstukken gevonden",
|
||||||
"LabelClickForMoreInfo": "Klik voor meer informatie",
|
"LabelClickForMoreInfo": "Klik voor meer informatie",
|
||||||
|
"LabelClickToUseCurrentValue": "Klik om huidige waarde te gebruiken",
|
||||||
"LabelClosePlayer": "Sluit speler",
|
"LabelClosePlayer": "Sluit speler",
|
||||||
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Series inklappen",
|
"LabelCollapseSeries": "Series inklappen",
|
||||||
|
"LabelCollapseSubSeries": "Subserie samenvouwen",
|
||||||
"LabelCollection": "Collectie",
|
"LabelCollection": "Collectie",
|
||||||
"LabelCollections": "Collecties",
|
"LabelCollections": "Collecties",
|
||||||
"LabelComplete": "Compleet",
|
"LabelComplete": "Compleet",
|
||||||
@@ -226,6 +276,7 @@
|
|||||||
"LabelContinueListening": "Verder Luisteren",
|
"LabelContinueListening": "Verder Luisteren",
|
||||||
"LabelContinueReading": "Verder lezen",
|
"LabelContinueReading": "Verder lezen",
|
||||||
"LabelContinueSeries": "Doorgaan met Serie",
|
"LabelContinueSeries": "Doorgaan met Serie",
|
||||||
|
"LabelCover": "Omslag",
|
||||||
"LabelCoverImageURL": "Coverafbeelding URL",
|
"LabelCoverImageURL": "Coverafbeelding URL",
|
||||||
"LabelCreatedAt": "Gecreëerd op",
|
"LabelCreatedAt": "Gecreëerd op",
|
||||||
"LabelCronExpression": "Cron-uitdrukking",
|
"LabelCronExpression": "Cron-uitdrukking",
|
||||||
@@ -234,38 +285,68 @@
|
|||||||
"LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:",
|
"LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:",
|
||||||
"LabelDatetime": "Datum-tijd",
|
"LabelDatetime": "Datum-tijd",
|
||||||
"LabelDays": "Dagen",
|
"LabelDays": "Dagen",
|
||||||
|
"LabelDeleteFromFileSystemCheckbox": "Verwijderen uit bestandssysteem (uncheck om alleen uit database te verwijderen)",
|
||||||
"LabelDescription": "Beschrijving",
|
"LabelDescription": "Beschrijving",
|
||||||
"LabelDeselectAll": "Deselecteer alle",
|
"LabelDeselectAll": "Deselecteer alle",
|
||||||
"LabelDevice": "Apparaat",
|
"LabelDevice": "Apparaat",
|
||||||
"LabelDeviceInfo": "Apparaat info",
|
"LabelDeviceInfo": "Apparaat info",
|
||||||
|
"LabelDeviceIsAvailableTo": "Apparaat is beschikbaar voor...",
|
||||||
"LabelDirectory": "Map",
|
"LabelDirectory": "Map",
|
||||||
"LabelDiscFromFilename": "Schijf uit bestandsnaam",
|
"LabelDiscFromFilename": "Schijf uit bestandsnaam",
|
||||||
"LabelDiscFromMetadata": "Schijf uit metadata",
|
"LabelDiscFromMetadata": "Schijf uit metadata",
|
||||||
"LabelDiscover": "Ontdekken",
|
"LabelDiscover": "Ontdekken",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
|
"LabelDownloadNEpisodes": "Download {0} afleveringen",
|
||||||
"LabelDuration": "Duur",
|
"LabelDuration": "Duur",
|
||||||
|
"LabelDurationComparisonExactMatch": "(exacte overeenkomst)",
|
||||||
|
"LabelDurationComparisonLonger": "({0} langer)",
|
||||||
|
"LabelDurationComparisonShorter": "({0} korter)",
|
||||||
"LabelDurationFound": "Gevonden duur:",
|
"LabelDurationFound": "Gevonden duur:",
|
||||||
"LabelEbook": "Ebook",
|
"LabelEbook": "Ebook",
|
||||||
"LabelEbooks": "Eboeken",
|
"LabelEbooks": "Eboeken",
|
||||||
"LabelEdit": "Wijzig",
|
"LabelEdit": "Wijzig",
|
||||||
|
"LabelEmail": "Email",
|
||||||
"LabelEmailSettingsFromAddress": "Van-adres",
|
"LabelEmailSettingsFromAddress": "Van-adres",
|
||||||
|
"LabelEmailSettingsRejectUnauthorized": "Ongeautoriseerde certificaten afwijzen",
|
||||||
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Het uitschakelen van SSL-certificaatvalidatie kan uw verbinding blootstellen aan beveiligingsrisico's, zoals man-in-the-middle-aanvallen. Schakel deze optie alleen uit als u de implicaties begrijpt en de mailserver waarmee u verbinding maakt vertrouwt.",
|
||||||
"LabelEmailSettingsSecure": "Veilig",
|
"LabelEmailSettingsSecure": "Veilig",
|
||||||
"LabelEmailSettingsSecureHelp": "Als 'waar', dan gebruikt de verbinding TLS om met de server te verbinden. Als 'onwaar', dan wordt TLS gebruikt als de server de STARTTLS-extensie ondersteunt. In de meeste gevallen kies je voor 'waar' verbindt met poort 465. Voo poort 587 of 25, laat op 'onwaar'. (van nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Als 'waar', dan gebruikt de verbinding TLS om met de server te verbinden. Als 'onwaar', dan wordt TLS gebruikt als de server de STARTTLS-extensie ondersteunt. In de meeste gevallen kies je voor 'waar' verbindt met poort 465. Voo poort 587 of 25, laat op 'onwaar'. (van nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "Test-adres",
|
"LabelEmailSettingsTestAddress": "Test-adres",
|
||||||
"LabelEmbeddedCover": "Ingesloten cover",
|
"LabelEmbeddedCover": "Ingesloten cover",
|
||||||
"LabelEnable": "Inschakelen",
|
"LabelEnable": "Inschakelen",
|
||||||
|
"LabelEncodingBackupLocation": "Er wordt een back-up van uw originele audiobestanden opgeslagen in:",
|
||||||
|
"LabelEncodingChaptersNotEmbedded": "Hoofdstukken zijn niet ingesloten in audioboeken met meerdere sporen.",
|
||||||
|
"LabelEncodingClearItemCache": "Zorg ervoor dat u de cache van items regelmatig wist.",
|
||||||
|
"LabelEncodingFinishedM4B": "Een voltooide M4B wordt in uw audioboekfolder geplaatst in:",
|
||||||
|
"LabelEncodingInfoEmbedded": "Metagegevens worden ingesloten in de audiotracks in uw audioboekmap.",
|
||||||
|
"LabelEncodingStartedNavigation": "Eenmaal de taak is gestart kan u weg navigeren van deze pagina.",
|
||||||
|
"LabelEncodingTimeWarning": "Encoding kan tot 30 minuten duren.",
|
||||||
|
"LabelEncodingWarningAdvancedSettings": "Waarschuwing: update deze instellingen niet tenzij u bekend bent met de coderingsopties van ffmpeg.",
|
||||||
|
"LabelEncodingWatcherDisabled": "Als u de watcher hebt uitgeschakeld, moet u het audioboek daarna opnieuw scannen.",
|
||||||
"LabelEnd": "Einde",
|
"LabelEnd": "Einde",
|
||||||
"LabelEndOfChapter": "Einde van het Hoofdstuk",
|
"LabelEndOfChapter": "Einde van het Hoofdstuk",
|
||||||
"LabelEpisode": "Aflevering",
|
"LabelEpisode": "Aflevering",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Aflevering niet gelinkt aan RSS feed",
|
||||||
|
"LabelEpisodeNumber": "Aflevering #{0}",
|
||||||
"LabelEpisodeTitle": "Afleveringtitel",
|
"LabelEpisodeTitle": "Afleveringtitel",
|
||||||
"LabelEpisodeType": "Afleveringtype",
|
"LabelEpisodeType": "Afleveringtype",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "Aflevering URL van RSS feed",
|
||||||
|
"LabelEpisodes": "Afleveringen",
|
||||||
|
"LabelEpisodic": "Episodisch",
|
||||||
"LabelExample": "Voorbeeld",
|
"LabelExample": "Voorbeeld",
|
||||||
|
"LabelExpandSeries": "Serie Uitvouwen",
|
||||||
|
"LabelExpandSubSeries": "Subserie Uitvouwen",
|
||||||
"LabelExplicit": "Expliciet",
|
"LabelExplicit": "Expliciet",
|
||||||
|
"LabelExplicitChecked": "Expliciet (gechecked)",
|
||||||
|
"LabelExplicitUnchecked": "Niet Expliciet (niet gechecked)",
|
||||||
|
"LabelExportOPML": "OPML exporteren",
|
||||||
"LabelFeedURL": "Feed URL",
|
"LabelFeedURL": "Feed URL",
|
||||||
"LabelFetchingMetadata": "Metadata ophalen",
|
"LabelFetchingMetadata": "Metadata ophalen",
|
||||||
"LabelFile": "Bestand",
|
"LabelFile": "Bestand",
|
||||||
"LabelFileBirthtime": "Aanmaaktijd bestand",
|
"LabelFileBirthtime": "Aanmaaktijd bestand",
|
||||||
|
"LabelFileBornDate": "Geboren {0}",
|
||||||
"LabelFileModified": "Bestand gewijzigd",
|
"LabelFileModified": "Bestand gewijzigd",
|
||||||
|
"LabelFileModifiedDate": "Gewijzigd {0}",
|
||||||
"LabelFilename": "Bestandsnaam",
|
"LabelFilename": "Bestandsnaam",
|
||||||
"LabelFilterByUser": "Filter op gebruiker",
|
"LabelFilterByUser": "Filter op gebruiker",
|
||||||
"LabelFindEpisodes": "Zoek afleveringen",
|
"LabelFindEpisodes": "Zoek afleveringen",
|
||||||
@@ -275,20 +356,27 @@
|
|||||||
"LabelFontBold": "Vetgedrukt",
|
"LabelFontBold": "Vetgedrukt",
|
||||||
"LabelFontBoldness": "Font Boldness",
|
"LabelFontBoldness": "Font Boldness",
|
||||||
"LabelFontFamily": "Lettertypefamilie",
|
"LabelFontFamily": "Lettertypefamilie",
|
||||||
|
"LabelFontItalic": "Cursief",
|
||||||
"LabelFontScale": "Lettertype schaal",
|
"LabelFontScale": "Lettertype schaal",
|
||||||
|
"LabelFontStrikethrough": "Doorgestreept",
|
||||||
"LabelFormat": "Formaat",
|
"LabelFormat": "Formaat",
|
||||||
|
"LabelFull": "Vol",
|
||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genres",
|
"LabelGenres": "Genres",
|
||||||
"LabelHardDeleteFile": "Hard-delete bestand",
|
"LabelHardDeleteFile": "Hard-delete bestand",
|
||||||
"LabelHasEbook": "Heeft Ebook",
|
"LabelHasEbook": "Heeft Ebook",
|
||||||
"LabelHasSupplementaryEbook": "Heeft aanvullend Ebook",
|
"LabelHasSupplementaryEbook": "Heeft aanvullend Ebook",
|
||||||
|
"LabelHideSubtitles": "Ondertitels Verstoppen",
|
||||||
|
"LabelHighestPriority": "Hoogste Prioriteit",
|
||||||
"LabelHost": "Host",
|
"LabelHost": "Host",
|
||||||
"LabelHour": "Uur",
|
"LabelHour": "Uur",
|
||||||
"LabelHours": "Uren",
|
"LabelHours": "Uren",
|
||||||
"LabelIcon": "Icoon",
|
"LabelIcon": "Icoon",
|
||||||
|
"LabelImageURLFromTheWeb": "Afbeelding URL van web",
|
||||||
"LabelInProgress": "Bezig",
|
"LabelInProgress": "Bezig",
|
||||||
"LabelIncludeInTracklist": "Includeer in tracklijst",
|
"LabelIncludeInTracklist": "Includeer in tracklijst",
|
||||||
"LabelIncomplete": "Incompleet",
|
"LabelIncomplete": "Incompleet",
|
||||||
|
"LabelInterval": "Interval",
|
||||||
"LabelIntervalCustomDailyWeekly": "Aangepast dagelijks/wekelijks",
|
"LabelIntervalCustomDailyWeekly": "Aangepast dagelijks/wekelijks",
|
||||||
"LabelIntervalEvery12Hours": "Iedere 12 uur",
|
"LabelIntervalEvery12Hours": "Iedere 12 uur",
|
||||||
"LabelIntervalEvery15Minutes": "Iedere 15 minuten",
|
"LabelIntervalEvery15Minutes": "Iedere 15 minuten",
|
||||||
@@ -299,8 +387,11 @@
|
|||||||
"LabelIntervalEveryHour": "Ieder uur",
|
"LabelIntervalEveryHour": "Ieder uur",
|
||||||
"LabelInvert": "Omdraaien",
|
"LabelInvert": "Omdraaien",
|
||||||
"LabelItem": "Onderdeel",
|
"LabelItem": "Onderdeel",
|
||||||
|
"LabelJumpBackwardAmount": "Terugspoelen hoeveelheid",
|
||||||
|
"LabelJumpForwardAmount": "Vooruitspoelen hoeveelheid",
|
||||||
"LabelLanguage": "Taal",
|
"LabelLanguage": "Taal",
|
||||||
"LabelLanguageDefaultServer": "Standaard servertaal",
|
"LabelLanguageDefaultServer": "Standaard servertaal",
|
||||||
|
"LabelLanguages": "Talen",
|
||||||
"LabelLastBookAdded": "Laatst toegevoegde boek",
|
"LabelLastBookAdded": "Laatst toegevoegde boek",
|
||||||
"LabelLastBookUpdated": "Laatst bijgewerkte boek",
|
"LabelLastBookUpdated": "Laatst bijgewerkte boek",
|
||||||
"LabelLastSeen": "Laatst gezien",
|
"LabelLastSeen": "Laatst gezien",
|
||||||
@@ -312,20 +403,36 @@
|
|||||||
"LabelLess": "Minder",
|
"LabelLess": "Minder",
|
||||||
"LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken",
|
"LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken",
|
||||||
"LabelLibrary": "Bibliotheek",
|
"LabelLibrary": "Bibliotheek",
|
||||||
|
"LabelLibraryFilterSublistEmpty": "Nee {0}",
|
||||||
"LabelLibraryItem": "Bibliotheekonderdeel",
|
"LabelLibraryItem": "Bibliotheekonderdeel",
|
||||||
"LabelLibraryName": "Bibliotheeknaam",
|
"LabelLibraryName": "Bibliotheeknaam",
|
||||||
"LabelLimit": "Limiet",
|
"LabelLimit": "Limiet",
|
||||||
"LabelLineSpacing": "Regelruimte",
|
"LabelLineSpacing": "Regelruimte",
|
||||||
"LabelListenAgain": "Opnieuw Beluisteren",
|
"LabelListenAgain": "Opnieuw Beluisteren",
|
||||||
|
"LabelLogLevelDebug": "Debug",
|
||||||
|
"LabelLogLevelInfo": "Informatie",
|
||||||
"LabelLogLevelWarn": "Waarschuwing",
|
"LabelLogLevelWarn": "Waarschuwing",
|
||||||
"LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum",
|
"LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum",
|
||||||
|
"LabelLowestPriority": "Laagste Prioriteit",
|
||||||
|
"LabelMatchExistingUsersBy": "Bestaande gebruikers matchen op",
|
||||||
|
"LabelMatchExistingUsersByDescription": "Wordt gebruikt om bestaande gebruikers te verbinden. Zodra ze verbonden zijn, worden gebruikers gekoppeld aan een unieke id van uw SSO-provider.",
|
||||||
|
"LabelMaxEpisodesToDownload": "Maximale # afleveringen om te downloaden. Gebruik 0 voor ongelimiteerd.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Maximale # nieuwe afleveringen om te downloaden per check",
|
||||||
|
"LabelMaxEpisodesToKeep": "Maximale # afleveringen om te houden",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "Waarde van 0 stelt geen maximumlimiet in. Nadat een nieuwe aflevering automatisch is gedownload, wordt de oudste aflevering verwijderd als u meer dan X afleveringen hebt. Hiermee wordt slechts 1 aflevering per nieuwe download verwijderd.",
|
||||||
"LabelMediaPlayer": "Mediaspeler",
|
"LabelMediaPlayer": "Mediaspeler",
|
||||||
"LabelMediaType": "Mediatype",
|
"LabelMediaType": "Mediatype",
|
||||||
"LabelMetaTag": "Meta-tag",
|
"LabelMetaTag": "Meta-tag",
|
||||||
"LabelMetaTags": "Meta-tags",
|
"LabelMetaTags": "Meta-tags",
|
||||||
|
"LabelMetadataOrderOfPrecedenceDescription": "Metadatabronnen met een hogere prioriteit zullen metadatabronnen met een lagere prioriteit overschrijven",
|
||||||
"LabelMetadataProvider": "Metadatabron",
|
"LabelMetadataProvider": "Metadatabron",
|
||||||
"LabelMinute": "Minuut",
|
"LabelMinute": "Minuut",
|
||||||
|
"LabelMinutes": "Minuten",
|
||||||
"LabelMissing": "Ontbrekend",
|
"LabelMissing": "Ontbrekend",
|
||||||
|
"LabelMissingEbook": "Heeft geen ebook",
|
||||||
|
"LabelMissingSupplementaryEbook": "Heeft geen supplementair ebook",
|
||||||
|
"LabelMobileRedirectURIs": "Toegestane mobiele omleidings-URL's",
|
||||||
|
"LabelMobileRedirectURIsDescription": "Dit is een whitelist met geldige redirect-URI's voor mobiele apps. De standaard is <code>audiobookshelf://oauth</code>, die u kunt verwijderen of aanvullen met extra URI's voor integratie met apps van derden. Als u een asterisk (<code>*</code>) als enige invoer gebruikt, is elke URI toegestaan.",
|
||||||
"LabelMore": "Meer",
|
"LabelMore": "Meer",
|
||||||
"LabelMoreInfo": "Meer info",
|
"LabelMoreInfo": "Meer info",
|
||||||
"LabelName": "Naam",
|
"LabelName": "Naam",
|
||||||
@@ -337,10 +444,12 @@
|
|||||||
"LabelNewestEpisodes": "Nieuwste Afleveringen",
|
"LabelNewestEpisodes": "Nieuwste Afleveringen",
|
||||||
"LabelNextBackupDate": "Volgende back-up datum",
|
"LabelNextBackupDate": "Volgende back-up datum",
|
||||||
"LabelNextScheduledRun": "Volgende geplande run",
|
"LabelNextScheduledRun": "Volgende geplande run",
|
||||||
|
"LabelNoCustomMetadataProviders": "Geen custom metadata bronnen",
|
||||||
"LabelNoEpisodesSelected": "Geen afleveringen geselecteerd",
|
"LabelNoEpisodesSelected": "Geen afleveringen geselecteerd",
|
||||||
"LabelNotFinished": "Niet Voltooid",
|
"LabelNotFinished": "Niet Voltooid",
|
||||||
"LabelNotStarted": "Niet Gestart",
|
"LabelNotStarted": "Niet Gestart",
|
||||||
"LabelNotes": "Notities",
|
"LabelNotes": "Notities",
|
||||||
|
"LabelNotificationAppriseURL": "URL(s) van kennisgeving",
|
||||||
"LabelNotificationAvailableVariables": "Beschikbare variabelen",
|
"LabelNotificationAvailableVariables": "Beschikbare variabelen",
|
||||||
"LabelNotificationBodyTemplate": "Body-template",
|
"LabelNotificationBodyTemplate": "Body-template",
|
||||||
"LabelNotificationEvent": "Notificatie gebeurtenis",
|
"LabelNotificationEvent": "Notificatie gebeurtenis",
|
||||||
@@ -351,10 +460,15 @@
|
|||||||
"LabelNotificationsMaxQueueSizeHelp": "Gebeurtenissen zijn beperkt tot 1 aftrap per seconde. Gebeurtenissen zullen genegeerd worden als de rij aan de maximale grootte zit. Dit voorkomt notificatie-spamming.",
|
"LabelNotificationsMaxQueueSizeHelp": "Gebeurtenissen zijn beperkt tot 1 aftrap per seconde. Gebeurtenissen zullen genegeerd worden als de rij aan de maximale grootte zit. Dit voorkomt notificatie-spamming.",
|
||||||
"LabelNumberOfBooks": "Aantal Boeken",
|
"LabelNumberOfBooks": "Aantal Boeken",
|
||||||
"LabelNumberOfEpisodes": "# afleveringen",
|
"LabelNumberOfEpisodes": "# afleveringen",
|
||||||
|
"LabelOpenIDAdvancedPermsClaimDescription": "Naam van de OpenID-claim die geavanceerde machtigingen bevat voor gebruikersacties binnen de applicatie die van toepassing zijn op niet-beheerdersrollen (<b>indien geconfigureerd</b>). Als de claim ontbreekt in het antwoord, wordt toegang tot ABS geweigerd. Als er één optie ontbreekt, wordt deze behandeld als <code>false</code>. Zorg ervoor dat de claim van de identiteitsprovider overeenkomt met de verwachte structuur:",
|
||||||
|
"LabelOpenIDClaims": "Laat de volgende opties leeg om geavanceerde groeps- en machtigingstoewijzing uit te schakelen en de groep 'Gebruiker' automatisch toe te wijzen.",
|
||||||
|
"LabelOpenIDGroupClaimDescription": "Naam van de OpenID-claim die een lijst met de groepen van de gebruiker bevat. Vaak aangeduid als <code>groepen</code>. <b>Indien geconfigureerd</b>, zal de applicatie automatisch rollen toewijzen op basis van de groepslidmaatschappen van de gebruiker, op voorwaarde dat deze groepen hoofdlettergevoelig 'admin', 'gebruiker' of 'gast' worden genoemd in de claim. De claim moet een lijst bevatten en als een gebruiker tot meerdere groepen behoort, zal de applicatie de rol toewijzen die overeenkomt met het hoogste toegangsniveau. Als er geen groep overeenkomt, wordt de toegang geweigerd.",
|
||||||
"LabelOpenRSSFeed": "Open RSS-feed",
|
"LabelOpenRSSFeed": "Open RSS-feed",
|
||||||
"LabelOverwrite": "Overschrijf",
|
"LabelOverwrite": "Overschrijf",
|
||||||
|
"LabelPaginationPageXOfY": "Pagina {0} van {1}",
|
||||||
"LabelPassword": "Wachtwoord",
|
"LabelPassword": "Wachtwoord",
|
||||||
"LabelPath": "Pad",
|
"LabelPath": "Pad",
|
||||||
|
"LabelPermanent": "Permanent",
|
||||||
"LabelPermissionsAccessAllLibraries": "Heeft toegang tot all bibliotheken",
|
"LabelPermissionsAccessAllLibraries": "Heeft toegang tot all bibliotheken",
|
||||||
"LabelPermissionsAccessAllTags": "Heeft toegang tot alle tags",
|
"LabelPermissionsAccessAllTags": "Heeft toegang tot alle tags",
|
||||||
"LabelPermissionsAccessExplicitContent": "Heeft toegang tot expliciete inhoud",
|
"LabelPermissionsAccessExplicitContent": "Heeft toegang tot expliciete inhoud",
|
||||||
@@ -362,21 +476,29 @@
|
|||||||
"LabelPermissionsDownload": "Kan downloaden",
|
"LabelPermissionsDownload": "Kan downloaden",
|
||||||
"LabelPermissionsUpdate": "Kan bijwerken",
|
"LabelPermissionsUpdate": "Kan bijwerken",
|
||||||
"LabelPermissionsUpload": "Kan uploaden",
|
"LabelPermissionsUpload": "Kan uploaden",
|
||||||
|
"LabelPersonalYearReview": "Jouw jaar in review ({0})",
|
||||||
"LabelPhotoPathURL": "Foto pad/URL",
|
"LabelPhotoPathURL": "Foto pad/URL",
|
||||||
"LabelPlayMethod": "Afspeelwijze",
|
"LabelPlayMethod": "Afspeelwijze",
|
||||||
|
"LabelPlayerChapterNumberMarker": "{0} van {1}",
|
||||||
"LabelPlaylists": "Afspeellijsten",
|
"LabelPlaylists": "Afspeellijsten",
|
||||||
"LabelPodcast": "Podcast",
|
"LabelPodcast": "Podcast",
|
||||||
"LabelPodcastSearchRegion": "Podcast zoekregio",
|
"LabelPodcastSearchRegion": "Podcast zoekregio",
|
||||||
"LabelPodcastType": "Podcasttype",
|
"LabelPodcastType": "Podcasttype",
|
||||||
|
"LabelPodcasts": "Podcasts",
|
||||||
"LabelPort": "Poort",
|
"LabelPort": "Poort",
|
||||||
"LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)",
|
"LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)",
|
||||||
"LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen",
|
"LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen",
|
||||||
"LabelPrimaryEbook": "Primair ebook",
|
"LabelPrimaryEbook": "Primair ebook",
|
||||||
"LabelProgress": "Voortgang",
|
"LabelProgress": "Voortgang",
|
||||||
"LabelProvider": "Bron",
|
"LabelProvider": "Bron",
|
||||||
|
"LabelProviderAuthorizationValue": "Autorisatie Header Waarde",
|
||||||
"LabelPubDate": "Publicatiedatum",
|
"LabelPubDate": "Publicatiedatum",
|
||||||
"LabelPublishYear": "Jaar van uitgave",
|
"LabelPublishYear": "Jaar van uitgave",
|
||||||
|
"LabelPublishedDate": "Gepubliceerd {0}",
|
||||||
|
"LabelPublishedDecade": "Gepubliceerd Decennium",
|
||||||
|
"LabelPublishedDecades": "Gepubliceerd Decennia",
|
||||||
"LabelPublisher": "Uitgever",
|
"LabelPublisher": "Uitgever",
|
||||||
|
"LabelPublishers": "Uitgevers",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "Aangepast e-mailadres eigenaar",
|
"LabelRSSFeedCustomOwnerEmail": "Aangepast e-mailadres eigenaar",
|
||||||
"LabelRSSFeedCustomOwnerName": "Aangepaste naam eigenaar",
|
"LabelRSSFeedCustomOwnerName": "Aangepaste naam eigenaar",
|
||||||
"LabelRSSFeedOpen": "RSS-feed open",
|
"LabelRSSFeedOpen": "RSS-feed open",
|
||||||
@@ -384,31 +506,45 @@
|
|||||||
"LabelRSSFeedSlug": "RSS-feed slug",
|
"LabelRSSFeedSlug": "RSS-feed slug",
|
||||||
"LabelRSSFeedURL": "RSS-feed URL",
|
"LabelRSSFeedURL": "RSS-feed URL",
|
||||||
"LabelRandomly": "Willekeurig",
|
"LabelRandomly": "Willekeurig",
|
||||||
|
"LabelReAddSeriesToContinueListening": "Serie opnieuw toevoegen aan verder luisteren",
|
||||||
"LabelRead": "Lees",
|
"LabelRead": "Lees",
|
||||||
"LabelReadAgain": "Opnieuw Lezen",
|
"LabelReadAgain": "Opnieuw Lezen",
|
||||||
"LabelReadEbookWithoutProgress": "Lees ebook zonder voortgang bij te houden",
|
"LabelReadEbookWithoutProgress": "Lees ebook zonder voortgang bij te houden",
|
||||||
"LabelRecentSeries": "Recente Serie",
|
"LabelRecentSeries": "Recente Serie",
|
||||||
"LabelRecentlyAdded": "Recent Toegevoegd",
|
"LabelRecentlyAdded": "Recent Toegevoegd",
|
||||||
"LabelRecommended": "Aangeraden",
|
"LabelRecommended": "Aangeraden",
|
||||||
|
"LabelRedo": "Opnieuw",
|
||||||
"LabelRegion": "Regio",
|
"LabelRegion": "Regio",
|
||||||
"LabelReleaseDate": "Verschijningsdatum",
|
"LabelReleaseDate": "Verschijningsdatum",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Verwijder alle metadata.abs bestanden",
|
||||||
|
"LabelRemoveAllMetadataJson": "Verwijder alle metadata.json bestanden",
|
||||||
"LabelRemoveCover": "Verwijder cover",
|
"LabelRemoveCover": "Verwijder cover",
|
||||||
|
"LabelRemoveMetadataFile": "Verwijder metadata bestanden in bibliotheek item folders",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Verwijder alle metadata.json en metadata.abs bestanden in uw {0} folders.",
|
||||||
|
"LabelRowsPerPage": "Rijen per pagina",
|
||||||
"LabelSearchTerm": "Zoekterm",
|
"LabelSearchTerm": "Zoekterm",
|
||||||
"LabelSearchTitle": "Zoek titel",
|
"LabelSearchTitle": "Zoek titel",
|
||||||
"LabelSearchTitleOrASIN": "Zoek titel of ASIN",
|
"LabelSearchTitleOrASIN": "Zoek titel of ASIN",
|
||||||
"LabelSeason": "Seizoen",
|
"LabelSeason": "Seizoen",
|
||||||
|
"LabelSeasonNumber": "Seizoen #{0}",
|
||||||
|
"LabelSelectAll": "Alles selecteren",
|
||||||
"LabelSelectAllEpisodes": "Selecteer alle afleveringen",
|
"LabelSelectAllEpisodes": "Selecteer alle afleveringen",
|
||||||
"LabelSelectEpisodesShowing": "Selecteer {0} afleveringen laten zien",
|
"LabelSelectEpisodesShowing": "Selecteer {0} afleveringen laten zien",
|
||||||
|
"LabelSelectUsers": "Selecteer gebruikers",
|
||||||
"LabelSendEbookToDevice": "Stuur ebook naar...",
|
"LabelSendEbookToDevice": "Stuur ebook naar...",
|
||||||
"LabelSequence": "Sequentie",
|
"LabelSequence": "Sequentie",
|
||||||
|
"LabelSerial": "Serie",
|
||||||
"LabelSeries": "Serie",
|
"LabelSeries": "Serie",
|
||||||
"LabelSeriesName": "Naam serie",
|
"LabelSeriesName": "Naam serie",
|
||||||
"LabelSeriesProgress": "Voortgang serie",
|
"LabelSeriesProgress": "Voortgang serie",
|
||||||
|
"LabelServerLogLevel": "Server Log Niveau",
|
||||||
|
"LabelServerYearReview": "Server Jaar in Review ({0})",
|
||||||
"LabelSetEbookAsPrimary": "Stel in als primair",
|
"LabelSetEbookAsPrimary": "Stel in als primair",
|
||||||
"LabelSetEbookAsSupplementary": "Stel in als supplementair",
|
"LabelSetEbookAsSupplementary": "Stel in als supplementair",
|
||||||
"LabelSettingsAudiobooksOnly": "Alleen audiobooks",
|
"LabelSettingsAudiobooksOnly": "Alleen audiobooks",
|
||||||
"LabelSettingsAudiobooksOnlyHelp": "Deze instelling inschakelen zorgt ervoor dat ebook-bestanden genegeerd worden tenzij ze in een audiobook-map staan, in welk geval ze worden ingesteld als supplementaire ebooks",
|
"LabelSettingsAudiobooksOnlyHelp": "Deze instelling inschakelen zorgt ervoor dat ebook-bestanden genegeerd worden tenzij ze in een audiobook-map staan, in welk geval ze worden ingesteld als supplementaire ebooks",
|
||||||
"LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken",
|
"LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken",
|
||||||
|
"LabelSettingsChromecastSupport": "Chromecast ondersteuning",
|
||||||
"LabelSettingsDateFormat": "Datum format",
|
"LabelSettingsDateFormat": "Datum format",
|
||||||
"LabelSettingsDisableWatcher": "Watcher uitschakelen",
|
"LabelSettingsDisableWatcher": "Watcher uitschakelen",
|
||||||
"LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen",
|
"LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen",
|
||||||
@@ -416,6 +552,8 @@
|
|||||||
"LabelSettingsEnableWatcher": "Watcher inschakelen",
|
"LabelSettingsEnableWatcher": "Watcher inschakelen",
|
||||||
"LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen",
|
"LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen",
|
||||||
"LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server",
|
"LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server",
|
||||||
|
"LabelSettingsEpubsAllowScriptedContent": "Sta scripted content toe in epubs",
|
||||||
|
"LabelSettingsEpubsAllowScriptedContentHelp": "Sta toe dat epub-bestanden scripts uitvoeren. Het wordt aanbevolen om deze instelling uitgeschakeld te houden, tenzij u de bron van de epub-bestanden vertrouwt.",
|
||||||
"LabelSettingsExperimentalFeatures": "Experimentele functies",
|
"LabelSettingsExperimentalFeatures": "Experimentele functies",
|
||||||
"LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.",
|
"LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.",
|
||||||
"LabelSettingsFindCovers": "Zoek covers",
|
"LabelSettingsFindCovers": "Zoek covers",
|
||||||
@@ -424,6 +562,8 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Series die slechts een enkel boek bevatten worden verborgen op de seriespagina en de homepagina-planken.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Series die slechts een enkel boek bevatten worden verborgen op de seriespagina en de homepagina-planken.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina",
|
"LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina",
|
||||||
"LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek",
|
"LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek",
|
||||||
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Sla eedere boeken in Serie Verderzetten over",
|
||||||
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "De Continue Series home page shelf toont het eerste boek dat nog niet is begonnen in series waarvan er minstens één is voltooid en er geen boeken in uitvoering zijn. Als u deze instelling inschakelt, wordt de serie voortgezet vanaf het boek dat het verst is voltooid in plaats van het eerste boek dat nog niet is begonnen.",
|
||||||
"LabelSettingsParseSubtitles": "Parseer subtitel",
|
"LabelSettingsParseSubtitles": "Parseer subtitel",
|
||||||
"LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"",
|
"LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"",
|
||||||
"LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata",
|
"LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata",
|
||||||
@@ -439,9 +579,15 @@
|
|||||||
"LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel",
|
"LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel",
|
||||||
"LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden",
|
"LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden",
|
||||||
"LabelSettingsTimeFormat": "Tijdformat",
|
"LabelSettingsTimeFormat": "Tijdformat",
|
||||||
|
"LabelShare": "Delen",
|
||||||
|
"LabelShareOpen": "Delen Open",
|
||||||
|
"LabelShareURL": "URL Delen",
|
||||||
"LabelShowAll": "Toon alle",
|
"LabelShowAll": "Toon alle",
|
||||||
|
"LabelShowSeconds": "Laat seconden zien",
|
||||||
|
"LabelShowSubtitles": "Laat Ondertitels zien",
|
||||||
"LabelSize": "Grootte",
|
"LabelSize": "Grootte",
|
||||||
"LabelSleepTimer": "Slaaptimer",
|
"LabelSleepTimer": "Slaaptimer",
|
||||||
|
"LabelSlug": "Slak",
|
||||||
"LabelStart": "Start",
|
"LabelStart": "Start",
|
||||||
"LabelStartTime": "Starttijd",
|
"LabelStartTime": "Starttijd",
|
||||||
"LabelStarted": "Gestart",
|
"LabelStarted": "Gestart",
|
||||||
@@ -468,10 +614,19 @@
|
|||||||
"LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker",
|
"LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker",
|
||||||
"LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker",
|
"LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker",
|
||||||
"LabelTasks": "Lopende taken",
|
"LabelTasks": "Lopende taken",
|
||||||
|
"LabelTextEditorBulletedList": "Opgesomde lijst",
|
||||||
|
"LabelTextEditorLink": "Link",
|
||||||
|
"LabelTextEditorNumberedList": "Genummerde lijst",
|
||||||
|
"LabelTextEditorUnlink": "Unlink",
|
||||||
"LabelTheme": "Thema",
|
"LabelTheme": "Thema",
|
||||||
"LabelThemeDark": "Donker",
|
"LabelThemeDark": "Donker",
|
||||||
"LabelThemeLight": "Licht",
|
"LabelThemeLight": "Licht",
|
||||||
"LabelTimeBase": "Tijdsbasis",
|
"LabelTimeBase": "Tijdsbasis",
|
||||||
|
"LabelTimeDurationXHours": "{0} Uren",
|
||||||
|
"LabelTimeDurationXMinutes": "{0} minuten",
|
||||||
|
"LabelTimeDurationXSeconds": "{0} seconden",
|
||||||
|
"LabelTimeInMinutes": "Tijd in minuten",
|
||||||
|
"LabelTimeLeft": "{0} over",
|
||||||
"LabelTimeListened": "Tijd geluisterd",
|
"LabelTimeListened": "Tijd geluisterd",
|
||||||
"LabelTimeListenedToday": "Tijd geluisterd vandaag",
|
"LabelTimeListenedToday": "Tijd geluisterd vandaag",
|
||||||
"LabelTimeRemaining": "{0} te gaan",
|
"LabelTimeRemaining": "{0} te gaan",
|
||||||
@@ -479,6 +634,7 @@
|
|||||||
"LabelTitle": "Titel",
|
"LabelTitle": "Titel",
|
||||||
"LabelToolsEmbedMetadata": "Metadata insluiten",
|
"LabelToolsEmbedMetadata": "Metadata insluiten",
|
||||||
"LabelToolsEmbedMetadataDescription": "Metadata insluiten in audiobestanden, inclusief coverafbeelding en hoofdstukken.",
|
"LabelToolsEmbedMetadataDescription": "Metadata insluiten in audiobestanden, inclusief coverafbeelding en hoofdstukken.",
|
||||||
|
"LabelToolsM4bEncoder": "M4B Encoder",
|
||||||
"LabelToolsMakeM4b": "Maak M4B-audioboekbestand",
|
"LabelToolsMakeM4b": "Maak M4B-audioboekbestand",
|
||||||
"LabelToolsMakeM4bDescription": "Genereer een .M4B-audioboekbestand met ingesloten metadata, coverafbeelding en hoofdstukken.",
|
"LabelToolsMakeM4bDescription": "Genereer een .M4B-audioboekbestand met ingesloten metadata, coverafbeelding en hoofdstukken.",
|
||||||
"LabelToolsSplitM4b": "Splitst M4B in MP3's",
|
"LabelToolsSplitM4b": "Splitst M4B in MP3's",
|
||||||
@@ -488,12 +644,15 @@
|
|||||||
"LabelTrackFromFilename": "Track vanuit bestandsnaam",
|
"LabelTrackFromFilename": "Track vanuit bestandsnaam",
|
||||||
"LabelTrackFromMetadata": "Track vanuit metadata",
|
"LabelTrackFromMetadata": "Track vanuit metadata",
|
||||||
"LabelTracks": "Audiosporen",
|
"LabelTracks": "Audiosporen",
|
||||||
|
"LabelTracksMultiTrack": "Multi-spoor",
|
||||||
"LabelTracksNone": "Geen tracks",
|
"LabelTracksNone": "Geen tracks",
|
||||||
"LabelTracksSingleTrack": "Enkele track",
|
"LabelTracksSingleTrack": "Enkele track",
|
||||||
|
"LabelTrailer": "Trailer",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Onverkort",
|
"LabelUnabridged": "Onverkort",
|
||||||
"LabelUndo": "Ongedaan maken",
|
"LabelUndo": "Ongedaan maken",
|
||||||
"LabelUnknown": "Onbekend",
|
"LabelUnknown": "Onbekend",
|
||||||
|
"LabelUnknownPublishDate": "Onbekende uitgeefdatum",
|
||||||
"LabelUpdateCover": "Cover bijwerken",
|
"LabelUpdateCover": "Cover bijwerken",
|
||||||
"LabelUpdateCoverHelp": "Sta overschrijven van bestaande covers toe voor de geselecteerde boeken wanneer een match is gevonden",
|
"LabelUpdateCoverHelp": "Sta overschrijven van bestaande covers toe voor de geselecteerde boeken wanneer een match is gevonden",
|
||||||
"LabelUpdateDetails": "Details bijwerken",
|
"LabelUpdateDetails": "Details bijwerken",
|
||||||
@@ -501,16 +660,25 @@
|
|||||||
"LabelUpdatedAt": "Bijgewerkt op",
|
"LabelUpdatedAt": "Bijgewerkt op",
|
||||||
"LabelUploaderDragAndDrop": "Slepen & neerzeten van bestanden of mappen",
|
"LabelUploaderDragAndDrop": "Slepen & neerzeten van bestanden of mappen",
|
||||||
"LabelUploaderDropFiles": "Bestanden neerzetten",
|
"LabelUploaderDropFiles": "Bestanden neerzetten",
|
||||||
|
"LabelUploaderItemFetchMetadataHelp": "Automatisch titel, auteur en serie ophalen",
|
||||||
|
"LabelUseAdvancedOptions": "Gebruik Geavanceerde Instellingen",
|
||||||
"LabelUseChapterTrack": "Gebruik hoofdstuktrack",
|
"LabelUseChapterTrack": "Gebruik hoofdstuktrack",
|
||||||
"LabelUseFullTrack": "Gebruik volledige track",
|
"LabelUseFullTrack": "Gebruik volledige track",
|
||||||
|
"LabelUseZeroForUnlimited": "Gebruik 0 voor ongelimiteerd",
|
||||||
"LabelUser": "Gebruiker",
|
"LabelUser": "Gebruiker",
|
||||||
"LabelUsername": "Gebruikersnaam",
|
"LabelUsername": "Gebruikersnaam",
|
||||||
"LabelValue": "Waarde",
|
"LabelValue": "Waarde",
|
||||||
"LabelVersion": "Versie",
|
"LabelVersion": "Versie",
|
||||||
"LabelViewBookmarks": "Bekijk boekwijzers",
|
"LabelViewBookmarks": "Bekijk boekwijzers",
|
||||||
"LabelViewChapters": "Bekijk hoofdstukken",
|
"LabelViewChapters": "Bekijk hoofdstukken",
|
||||||
|
"LabelViewPlayerSettings": "Laat spelerinstellingen zien",
|
||||||
"LabelViewQueue": "Bekijk afspeelwachtrij",
|
"LabelViewQueue": "Bekijk afspeelwachtrij",
|
||||||
|
"LabelVolume": "Volume",
|
||||||
"LabelWeekdaysToRun": "Weekdagen om te draaien",
|
"LabelWeekdaysToRun": "Weekdagen om te draaien",
|
||||||
|
"LabelXBooks": "{0} boeken",
|
||||||
|
"LabelXItems": "{0} items",
|
||||||
|
"LabelYearReviewHide": "Verberg Jaar in Review",
|
||||||
|
"LabelYearReviewShow": "Laat Jaar in Review zien",
|
||||||
"LabelYourAudiobookDuration": "Je audioboekduur",
|
"LabelYourAudiobookDuration": "Je audioboekduur",
|
||||||
"LabelYourBookmarks": "Je boekwijzers",
|
"LabelYourBookmarks": "Je boekwijzers",
|
||||||
"LabelYourPlaylists": "Je afspeellijsten",
|
"LabelYourPlaylists": "Je afspeellijsten",
|
||||||
@@ -518,10 +686,14 @@
|
|||||||
"MessageAddToPlayerQueue": "Toevoegen aan wachtrij",
|
"MessageAddToPlayerQueue": "Toevoegen aan wachtrij",
|
||||||
"MessageAppriseDescription": "Om deze functie te gebruiken heb je een draaiende instantie van <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nodig of een api die dezelfde requests afhandelt. <br />De Apprise API Url moet het volledige URL-pad zijn om de notificatie te verzenden, b.v., als je API-instantie draait op <code>http://192.168.1.1:8337</code> dan zou je <code>http://192.168.1.1:8337/notify</code> gebruiken.",
|
"MessageAppriseDescription": "Om deze functie te gebruiken heb je een draaiende instantie van <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nodig of een api die dezelfde requests afhandelt. <br />De Apprise API Url moet het volledige URL-pad zijn om de notificatie te verzenden, b.v., als je API-instantie draait op <code>http://192.168.1.1:8337</code> dan zou je <code>http://192.168.1.1:8337/notify</code> gebruiken.",
|
||||||
"MessageBackupsDescription": "Back-ups omvatten gebruikers, gebruikers' voortgang, bibliotheekonderdeeldetails, serverinstellingen en afbeeldingen bewaard in <code>/metadata/items</code> & <code>/metadata/authors</code>. Back-ups <strong>bevatten niet</strong> de bestanden bewaard in je bibliotheekmappen.",
|
"MessageBackupsDescription": "Back-ups omvatten gebruikers, gebruikers' voortgang, bibliotheekonderdeeldetails, serverinstellingen en afbeeldingen bewaard in <code>/metadata/items</code> & <code>/metadata/authors</code>. Back-ups <strong>bevatten niet</strong> de bestanden bewaard in je bibliotheekmappen.",
|
||||||
|
"MessageBackupsLocationEditNote": "Let op: het bijwerken van de back-uplocatie zal bestaande back-ups niet verplaatsen of wijzigen",
|
||||||
|
"MessageBackupsLocationNoEditNote": "Let op: De back-uplocatie wordt ingesteld via een omgevingsvariabele en kan hier niet worden gewijzigd.",
|
||||||
|
"MessageBackupsLocationPathEmpty": "Backup locatie pad kan niet leeg zijn",
|
||||||
"MessageBatchQuickMatchDescription": "Quick Match zal proberen ontbrekende covers en metadata voor de geselecteerde onderdelen te matchten. Schakel de opties hieronder in om Quick Match toe te staan bestaande covers en/of metadata te overschrijven.",
|
"MessageBatchQuickMatchDescription": "Quick Match zal proberen ontbrekende covers en metadata voor de geselecteerde onderdelen te matchten. Schakel de opties hieronder in om Quick Match toe te staan bestaande covers en/of metadata te overschrijven.",
|
||||||
"MessageBookshelfNoCollections": "Je hebt nog geen collecties gemaakt",
|
"MessageBookshelfNoCollections": "Je hebt nog geen collecties gemaakt",
|
||||||
"MessageBookshelfNoRSSFeeds": "Geen RSS-feeds geopend",
|
"MessageBookshelfNoRSSFeeds": "Geen RSS-feeds geopend",
|
||||||
"MessageBookshelfNoResultsForFilter": "Geen resultaten voor filter \"{0}: {1}\"",
|
"MessageBookshelfNoResultsForFilter": "Geen resultaten voor filter \"{0}: {1}\"",
|
||||||
|
"MessageBookshelfNoResultsForQuery": "Geen resultaten voor query",
|
||||||
"MessageBookshelfNoSeries": "Je hebt geen series",
|
"MessageBookshelfNoSeries": "Je hebt geen series",
|
||||||
"MessageChapterEndIsAfter": "Hoofdstukeinde is na het einde van je audioboek",
|
"MessageChapterEndIsAfter": "Hoofdstukeinde is na het einde van je audioboek",
|
||||||
"MessageChapterErrorFirstNotZero": "Eerste hoofdstuk moet starten op 0",
|
"MessageChapterErrorFirstNotZero": "Eerste hoofdstuk moet starten op 0",
|
||||||
@@ -529,21 +701,37 @@
|
|||||||
"MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk",
|
"MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk",
|
||||||
"MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek",
|
"MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek",
|
||||||
"MessageCheckingCron": "Cron aan het checken...",
|
"MessageCheckingCron": "Cron aan het checken...",
|
||||||
|
"MessageConfirmCloseFeed": "Ben je zeker dat je deze feed wil sluiten?",
|
||||||
"MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?",
|
"MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?",
|
||||||
|
"MessageConfirmDeleteDevice": "Ben je zeker dat je e-reader apparaat \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmDeleteFile": "Dit verwijdert het bestand uit het bestandssysteem. Weet je het zeker?",
|
"MessageConfirmDeleteFile": "Dit verwijdert het bestand uit het bestandssysteem. Weet je het zeker?",
|
||||||
"MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?",
|
"MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?",
|
||||||
|
"MessageConfirmDeleteLibraryItem": "Hiermee wordt het bibliotheekitem uit de database en uw bestandssysteem verwijderd. Bent u zeker?",
|
||||||
|
"MessageConfirmDeleteLibraryItems": "Hiermee worden {0} bibliotheekitems uit de database en uw bestandssysteem verwijderd. Bent u zeker?",
|
||||||
|
"MessageConfirmDeleteMetadataProvider": "Weet u zeker dat u de aangepaste metadataprovider \"{0}\" wilt verwijderen?",
|
||||||
|
"MessageConfirmDeleteNotification": "Weet u zeker dat u deze melding wil verwijderen?",
|
||||||
"MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?",
|
"MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?",
|
||||||
|
"MessageConfirmEmbedMetadataInAudioFiles": "Weet u zeker dat u metagegevens wilt insluiten in {0} audiobestanden?",
|
||||||
"MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?",
|
"MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?",
|
||||||
"MessageConfirmMarkAllEpisodesFinished": "Weet je zeker dat je alle afleveringen als voltooid wil markeren?",
|
"MessageConfirmMarkAllEpisodesFinished": "Weet je zeker dat je alle afleveringen als voltooid wil markeren?",
|
||||||
"MessageConfirmMarkAllEpisodesNotFinished": "Weet je zeker dat je alle afleveringen als niet-voltooid wil markeren?",
|
"MessageConfirmMarkAllEpisodesNotFinished": "Weet je zeker dat je alle afleveringen als niet-voltooid wil markeren?",
|
||||||
|
"MessageConfirmMarkItemFinished": "Weet u zeker dat u \"{0}\" als voltooid wilt markeren?",
|
||||||
|
"MessageConfirmMarkItemNotFinished": "Weet u zeker dat u \"{0}\" als niet voltooid wilt markeren?",
|
||||||
"MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?",
|
"MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?",
|
||||||
"MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?",
|
"MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?",
|
||||||
|
"MessageConfirmNotificationTestTrigger": "Trigger deze melding met test data?",
|
||||||
|
"MessageConfirmPurgeCache": "Met Purge cache wordt de gehele directory op <code>/metadata/cache</code> verwijderd. <br /><br />Weet u zeker dat u de cachedirectory wilt verwijderen?",
|
||||||
|
"MessageConfirmPurgeItemsCache": "Met Purge items cache wordt de gehele directory op <code>/metadata/cache/items</code> verwijderd.<br />Weet u het zeker?",
|
||||||
|
"MessageConfirmQuickEmbed": "Waarschuwing! Quick embed maakt geen back-up van uw audiobestanden. Zorg ervoor dat u een back-up van uw audiobestanden hebt. <br><br>Wilt u doorgaan?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "Snel matchende afleveringen overschrijven details als er een match is gevonden. Alleen niet-matchende afleveringen worden bijgewerkt. Weet u het zeker?",
|
||||||
|
"MessageConfirmReScanLibraryItems": "Bent u zeker dat u {0} items opnieuw wil scannen?",
|
||||||
"MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?",
|
"MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?",
|
||||||
"MessageConfirmRemoveAuthor": "Weet je zeker dat je auteur \"{0}\" wil verwijderen?",
|
"MessageConfirmRemoveAuthor": "Weet je zeker dat je auteur \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?",
|
"MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?",
|
"MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?",
|
"MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Weet je zeker dat je {0} luistersessies wilt verwijderen?",
|
"MessageConfirmRemoveListeningSessions": "Weet je zeker dat je {0} luistersessies wilt verwijderen?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Bent u zeker dat u alle metadata wil verwijderen. {0} bestanden in uw bibliotheel item folders?",
|
||||||
"MessageConfirmRemoveNarrator": "Weet je zeker dat je verteller \"{0}\" wil verwijderen?",
|
"MessageConfirmRemoveNarrator": "Weet je zeker dat je verteller \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmRemovePlaylist": "Weet je zeker dat je je afspeellijst \"{0}\" wil verwijderen?",
|
"MessageConfirmRemovePlaylist": "Weet je zeker dat je je afspeellijst \"{0}\" wil verwijderen?",
|
||||||
"MessageConfirmRenameGenre": "Weet je zeker dat je genre \"{0}\" wil hernoemen naar \"{1}\" voor alle onderdelen?",
|
"MessageConfirmRenameGenre": "Weet je zeker dat je genre \"{0}\" wil hernoemen naar \"{1}\" voor alle onderdelen?",
|
||||||
@@ -552,11 +740,16 @@
|
|||||||
"MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?",
|
"MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?",
|
||||||
"MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.",
|
"MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.",
|
||||||
"MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".",
|
"MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".",
|
||||||
|
"MessageConfirmResetProgress": "Bet u zeker dat u uw voortgang wil resetten?",
|
||||||
"MessageConfirmSendEbookToDevice": "Weet je zeker dat je {0} ebook \"{1}\" naar apparaat \"{2}\" wil sturen?",
|
"MessageConfirmSendEbookToDevice": "Weet je zeker dat je {0} ebook \"{1}\" naar apparaat \"{2}\" wil sturen?",
|
||||||
|
"MessageConfirmUnlinkOpenId": "Bent u zeker dat u deze gebruiker wil ontkoppelen van OpenID?",
|
||||||
"MessageDownloadingEpisode": "Aflevering aan het dowloaden",
|
"MessageDownloadingEpisode": "Aflevering aan het dowloaden",
|
||||||
"MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde",
|
"MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde",
|
||||||
|
"MessageEmbedFailed": "Insluiten Mislukt!",
|
||||||
"MessageEmbedFinished": "Insluiting voltooid!",
|
"MessageEmbedFinished": "Insluiting voltooid!",
|
||||||
|
"MessageEmbedQueue": "In de wachtrij voor metadata-embed ({0} in wachtrij)",
|
||||||
"MessageEpisodesQueuedForDownload": "{0} aflevering(en) in de rij om te downloaden",
|
"MessageEpisodesQueuedForDownload": "{0} aflevering(en) in de rij om te downloaden",
|
||||||
|
"MessageEreaderDevices": "Om de levering van e-books te garanderen, moet u mogelijk bovenstaand e-mailadres opgeven als geldige afzender voor elk hieronder vermeld apparaat.",
|
||||||
"MessageFeedURLWillBe": "Feed URL zal {0} zijn",
|
"MessageFeedURLWillBe": "Feed URL zal {0} zijn",
|
||||||
"MessageFetching": "Aan het ophalen...",
|
"MessageFetching": "Aan het ophalen...",
|
||||||
"MessageForceReScanDescription": "zal alle bestanden opnieuw scannen als een verse scan. Audiobestanden ID3-tags, OPF-bestanden en textbestanden zullen als nieuw worden gescand.",
|
"MessageForceReScanDescription": "zal alle bestanden opnieuw scannen als een verse scan. Audiobestanden ID3-tags, OPF-bestanden en textbestanden zullen als nieuw worden gescand.",
|
||||||
@@ -568,6 +761,7 @@
|
|||||||
"MessageListeningSessionsInTheLastYear": "{0} luistersessies in het laatste jaar",
|
"MessageListeningSessionsInTheLastYear": "{0} luistersessies in het laatste jaar",
|
||||||
"MessageLoading": "Aan het laden...",
|
"MessageLoading": "Aan het laden...",
|
||||||
"MessageLoadingFolders": "Mappen aan het laden...",
|
"MessageLoadingFolders": "Mappen aan het laden...",
|
||||||
|
"MessageLogsDescription": "Logs worden opgeslagen in <code>/metadata/logs</code> als JSON-bestanden. Crashlogs worden opgeslagen in <code>/metadata/logs/crash_logs.txt</code>.",
|
||||||
"MessageM4BFailed": "M4B mislukt!",
|
"MessageM4BFailed": "M4B mislukt!",
|
||||||
"MessageM4BFinished": "M4B voltooid!",
|
"MessageM4BFinished": "M4B voltooid!",
|
||||||
"MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden",
|
"MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden",
|
||||||
@@ -584,6 +778,7 @@
|
|||||||
"MessageNoCollections": "Geen collecties",
|
"MessageNoCollections": "Geen collecties",
|
||||||
"MessageNoCoversFound": "Geen covers gevonden",
|
"MessageNoCoversFound": "Geen covers gevonden",
|
||||||
"MessageNoDescription": "Geen beschrijving",
|
"MessageNoDescription": "Geen beschrijving",
|
||||||
|
"MessageNoDevices": "Geen Apparaten",
|
||||||
"MessageNoDownloadsInProgress": "Geen downloads bezig op dit moment",
|
"MessageNoDownloadsInProgress": "Geen downloads bezig op dit moment",
|
||||||
"MessageNoDownloadsQueued": "Geen downloads in de wachtrij",
|
"MessageNoDownloadsQueued": "Geen downloads in de wachtrij",
|
||||||
"MessageNoEpisodeMatchesFound": "Geen afleveringsmatches gevonden",
|
"MessageNoEpisodeMatchesFound": "Geen afleveringsmatches gevonden",
|
||||||
@@ -597,6 +792,7 @@
|
|||||||
"MessageNoLogs": "Geen logs",
|
"MessageNoLogs": "Geen logs",
|
||||||
"MessageNoMediaProgress": "Geen mediavoortgang",
|
"MessageNoMediaProgress": "Geen mediavoortgang",
|
||||||
"MessageNoNotifications": "Geen notificaties",
|
"MessageNoNotifications": "Geen notificaties",
|
||||||
|
"MessageNoPodcastFeed": "Ongeldige podcast: Geen Feed",
|
||||||
"MessageNoPodcastsFound": "Geen podcasts gevonden",
|
"MessageNoPodcastsFound": "Geen podcasts gevonden",
|
||||||
"MessageNoResults": "Geen resultaten",
|
"MessageNoResults": "Geen resultaten",
|
||||||
"MessageNoSearchResultsFor": "Geen zoekresultaten voor \"{0}\"",
|
"MessageNoSearchResultsFor": "Geen zoekresultaten voor \"{0}\"",
|
||||||
@@ -606,11 +802,17 @@
|
|||||||
"MessageNoUpdatesWereNecessary": "Geen bijwerkingen waren noodzakelijk",
|
"MessageNoUpdatesWereNecessary": "Geen bijwerkingen waren noodzakelijk",
|
||||||
"MessageNoUserPlaylists": "Je hebt geen afspeellijsten",
|
"MessageNoUserPlaylists": "Je hebt geen afspeellijsten",
|
||||||
"MessageNotYetImplemented": "Nog niet geimplementeerd",
|
"MessageNotYetImplemented": "Nog niet geimplementeerd",
|
||||||
|
"MessageOpmlPreviewNote": "Let op: Dit is een preview van het geparseerde OPML-bestand. De werkelijke podcasttitel wordt overgenomen uit de RSS-feed.",
|
||||||
"MessageOr": "of",
|
"MessageOr": "of",
|
||||||
"MessagePauseChapter": "Pauzeer afspelen hoofdstuk",
|
"MessagePauseChapter": "Pauzeer afspelen hoofdstuk",
|
||||||
"MessagePlayChapter": "Luister naar begin van hoofdstuk",
|
"MessagePlayChapter": "Luister naar begin van hoofdstuk",
|
||||||
"MessagePlaylistCreateFromCollection": "Afspeellijst aanmaken vanuit collectie",
|
"MessagePlaylistCreateFromCollection": "Afspeellijst aanmaken vanuit collectie",
|
||||||
|
"MessagePleaseWait": "Even geduld...",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "Podcast heeft geen RSS-feed URL om te gebruiken voor matching",
|
"MessagePodcastHasNoRSSFeedForMatching": "Podcast heeft geen RSS-feed URL om te gebruiken voor matching",
|
||||||
|
"MessagePodcastSearchField": "Voer zoekterm of RSS-feed-URL in",
|
||||||
|
"MessageQuickEmbedInProgress": "Snelle inbedding in uitvoering",
|
||||||
|
"MessageQuickEmbedQueue": "In de wachtrij voor snelle insluiting ({0} in wachtrij)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Alle Afleveringen Snel Matchen",
|
||||||
"MessageQuickMatchDescription": "Vul lege onderdeeldetails & cover met eerste matchresultaat van '{0}'. Overschrijft geen details tenzij 'Prefereer gematchte metadata' serverinstelling is ingeschakeld.",
|
"MessageQuickMatchDescription": "Vul lege onderdeeldetails & cover met eerste matchresultaat van '{0}'. Overschrijft geen details tenzij 'Prefereer gematchte metadata' serverinstelling is ingeschakeld.",
|
||||||
"MessageRemoveChapter": "Verwijder hoofdstuk",
|
"MessageRemoveChapter": "Verwijder hoofdstuk",
|
||||||
"MessageRemoveEpisodes": "Verwijder {0} aflevering(en)",
|
"MessageRemoveEpisodes": "Verwijder {0} aflevering(en)",
|
||||||
@@ -621,10 +823,48 @@
|
|||||||
"MessageRestoreBackupConfirm": "Weet je zeker dat je wil herstellen met behulp van de back-up gemaakt op",
|
"MessageRestoreBackupConfirm": "Weet je zeker dat je wil herstellen met behulp van de back-up gemaakt op",
|
||||||
"MessageRestoreBackupWarning": "Herstellen met een back-up zal de volledige database in /config en de covers in /metadata/items & /metadata/authors overschrijven.<br /><br />Back-ups wijzigen geen bestanden in je bibliotheekmappen. Als je de serverinstelling gebruikt om covers en metadata in je bibliotheekmappen te bewaren dan worden deze niet geback-upt of overschreven.<br /><br />Alle clients die van je server gebruik maken zullen automatisch worden ververst.",
|
"MessageRestoreBackupWarning": "Herstellen met een back-up zal de volledige database in /config en de covers in /metadata/items & /metadata/authors overschrijven.<br /><br />Back-ups wijzigen geen bestanden in je bibliotheekmappen. Als je de serverinstelling gebruikt om covers en metadata in je bibliotheekmappen te bewaren dan worden deze niet geback-upt of overschreven.<br /><br />Alle clients die van je server gebruik maken zullen automatisch worden ververst.",
|
||||||
"MessageSearchResultsFor": "Zoekresultaten voor",
|
"MessageSearchResultsFor": "Zoekresultaten voor",
|
||||||
|
"MessageSelected": "{0} geselecteerd",
|
||||||
"MessageServerCouldNotBeReached": "Server niet bereikbaar",
|
"MessageServerCouldNotBeReached": "Server niet bereikbaar",
|
||||||
"MessageSetChaptersFromTracksDescription": "Stel hoofdstukken in met ieder audiobestand als een hoofdstuk en de audiobestandsnaam als hoofdstuktitel",
|
"MessageSetChaptersFromTracksDescription": "Stel hoofdstukken in met ieder audiobestand als een hoofdstuk en de audiobestandsnaam als hoofdstuktitel",
|
||||||
|
"MessageShareExpirationWillBe": "Vervaldatum is <strong>{0}</strong>",
|
||||||
"MessageShareExpiresIn": "Vervalt in {0}",
|
"MessageShareExpiresIn": "Vervalt in {0}",
|
||||||
|
"MessageShareURLWillBe": "De gedeelde URL wordt <strong>{0}</strong>",
|
||||||
"MessageStartPlaybackAtTime": "Afspelen van \"{0}\" beginnen op {1}?",
|
"MessageStartPlaybackAtTime": "Afspelen van \"{0}\" beginnen op {1}?",
|
||||||
|
"MessageTaskAudioFileNotWritable": "Audiobestand \"{0}\" is niet beschrijfbaar",
|
||||||
|
"MessageTaskCanceledByUser": "Taak geannuleerd door gebruiker",
|
||||||
|
"MessageTaskDownloadingEpisodeDescription": "Aflevering \"{0}\" downloaden",
|
||||||
|
"MessageTaskEmbeddingMetadata": "Metadata insluiten",
|
||||||
|
"MessageTaskEmbeddingMetadataDescription": "Metadata insluiten in audioboek \"{0}\"",
|
||||||
|
"MessageTaskEncodingM4b": "M4B Encoden",
|
||||||
|
"MessageTaskEncodingM4bDescription": "Audioboek \"{0}\" coderen in één m4b-bestand",
|
||||||
|
"MessageTaskFailed": "Mislukt",
|
||||||
|
"MessageTaskFailedToBackupAudioFile": "Het is niet gelukt om een back-up te maken van audiobestand \"{0}\"",
|
||||||
|
"MessageTaskFailedToCreateCacheDirectory": "Het is niet gelukt om een cachemap te maken",
|
||||||
|
"MessageTaskFailedToEmbedMetadataInFile": "Het is niet gelukt om metagegevens in bestand \"{0}\" in te sluiten",
|
||||||
|
"MessageTaskFailedToMergeAudioFiles": "Audiobestanden samenvoegen mislukt",
|
||||||
|
"MessageTaskFailedToMoveM4bFile": "m4b bestand verplaatsen mislukt",
|
||||||
|
"MessageTaskFailedToWriteMetadataFile": "Metadata bestand schrijven mislukt",
|
||||||
|
"MessageTaskMatchingBooksInLibrary": "Overeenkomende boeken in bibliotheek \"{0}\"",
|
||||||
|
"MessageTaskNoFilesToScan": "Geen bestanden om te scannen",
|
||||||
|
"MessageTaskOpmlImport": "OPML importeren",
|
||||||
|
"MessageTaskOpmlImportDescription": "Podcasts maken van {0} RSS feeds",
|
||||||
|
"MessageTaskOpmlImportFeed": "OPML feed importeren",
|
||||||
|
"MessageTaskOpmlImportFeedDescription": "RSS feed \"{0}\" importeren",
|
||||||
|
"MessageTaskOpmlImportFeedFailed": "Podcastfeed kon niet worden opgehaald",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastDescription": "Podcast \"{0}\" maken",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastExists": "Podcast bestaat al in pad",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastFailed": "Mislukt om podcast aan te maken",
|
||||||
|
"MessageTaskOpmlImportFinished": "{0} podcasts toegevoegd",
|
||||||
|
"MessageTaskOpmlParseFailed": "Het is niet gelukt om het OPML-bestand te parseren",
|
||||||
|
"MessageTaskOpmlParseFastFail": "Ongeldig OPML-bestand <opml> tag niet gevonden OF een <outline> tag is niet gevonden",
|
||||||
|
"MessageTaskOpmlParseNoneFound": "Geen feeds gevonden in OPML bestand",
|
||||||
|
"MessageTaskScanItemsAdded": "{0} toegevoegd",
|
||||||
|
"MessageTaskScanItemsMissing": "{0} missend",
|
||||||
|
"MessageTaskScanItemsUpdated": "{0} bijgewerkt",
|
||||||
|
"MessageTaskScanNoChangesNeeded": "Geen aanpassingen nodig",
|
||||||
|
"MessageTaskScanningFileChanges": "Scannen van bestandswijzigingen in \"{0}\"",
|
||||||
|
"MessageTaskScanningLibrary": "Scannen van bibliotheek \"{0}\"",
|
||||||
|
"MessageTaskTargetDirectoryNotWritable": "Doelmap is niet beschrijfbaar",
|
||||||
"MessageThinking": "Aan het denken...",
|
"MessageThinking": "Aan het denken...",
|
||||||
"MessageUploaderItemFailed": "Uploaden mislukt",
|
"MessageUploaderItemFailed": "Uploaden mislukt",
|
||||||
"MessageUploaderItemSuccess": "Uploaden gelukt!",
|
"MessageUploaderItemSuccess": "Uploaden gelukt!",
|
||||||
@@ -642,40 +882,104 @@
|
|||||||
"NoteUploaderFoldersWithMediaFiles": "Mappen met mediabestanden zullen worden behandeld als aparte bibliotheekonderdelen.",
|
"NoteUploaderFoldersWithMediaFiles": "Mappen met mediabestanden zullen worden behandeld als aparte bibliotheekonderdelen.",
|
||||||
"NoteUploaderOnlyAudioFiles": "Bij uploaden van uitsluitend audiobestanden wordt ieder audiobestand als apart audiobook worden behandeld.",
|
"NoteUploaderOnlyAudioFiles": "Bij uploaden van uitsluitend audiobestanden wordt ieder audiobestand als apart audiobook worden behandeld.",
|
||||||
"NoteUploaderUnsupportedFiles": "Niet-ondersteunde bestanden worden genegeerd. Bij het kiezen of neerzetten van een map worden andere bestanden die niet in de map staan genegeerd.",
|
"NoteUploaderUnsupportedFiles": "Niet-ondersteunde bestanden worden genegeerd. Bij het kiezen of neerzetten van een map worden andere bestanden die niet in de map staan genegeerd.",
|
||||||
|
"NotificationOnBackupCompletedDescription": "Wordt geactiveerd wanneer een back-up is voltooid",
|
||||||
|
"NotificationOnBackupFailedDescription": "Wordt geactiveerd wanneer een back-up mislukt",
|
||||||
|
"NotificationOnEpisodeDownloadedDescription": "Wordt geactiveerd wanneer een podcastaflevering automatisch wordt gedownload",
|
||||||
|
"NotificationOnTestDescription": "Event voor het testen van het notificatiesysteem",
|
||||||
"PlaceholderNewCollection": "Nieuwe naam collectie",
|
"PlaceholderNewCollection": "Nieuwe naam collectie",
|
||||||
"PlaceholderNewFolderPath": "Nieuwe locatie map",
|
"PlaceholderNewFolderPath": "Nieuwe locatie map",
|
||||||
"PlaceholderNewPlaylist": "Nieuwe naam afspeellijst",
|
"PlaceholderNewPlaylist": "Nieuwe naam afspeellijst",
|
||||||
"PlaceholderSearch": "Zoeken..",
|
"PlaceholderSearch": "Zoeken..",
|
||||||
"PlaceholderSearchEpisode": "Aflevering zoeken..",
|
"PlaceholderSearchEpisode": "Aflevering zoeken..",
|
||||||
|
"StatsAuthorsAdded": "auteurs toegevoegd",
|
||||||
|
"StatsBooksAdded": "boeken toegevoegd",
|
||||||
|
"StatsBooksAdditional": "Enkele toevoegingen zijn…",
|
||||||
|
"StatsBooksFinished": "boeken voltooid",
|
||||||
|
"StatsBooksFinishedThisYear": "Enkele boeken voltooid dit jaar…",
|
||||||
|
"StatsBooksListenedTo": "geluisterde boeken",
|
||||||
|
"StatsCollectionGrewTo": "Je boeken collectie groeide tot…",
|
||||||
|
"StatsSessions": "sessies",
|
||||||
|
"StatsSpentListening": "tijd geluisterd",
|
||||||
|
"StatsTopAuthor": "TOP AUTEUR",
|
||||||
|
"StatsTopAuthors": "TOP AUTEURS",
|
||||||
|
"StatsTopGenre": "TOP GENRE",
|
||||||
|
"StatsTopGenres": "TOP GENRES",
|
||||||
|
"StatsTopMonth": "TOP MAAND",
|
||||||
|
"StatsTopNarrator": "TOP VERTELLER",
|
||||||
|
"StatsTopNarrators": "TOP VERTELLERS",
|
||||||
|
"StatsTotalDuration": "Met een totale tijd van…",
|
||||||
|
"StatsYearInReview": "JAAR IN REVIEW",
|
||||||
"ToastAccountUpdateSuccess": "Account bijgewerkt",
|
"ToastAccountUpdateSuccess": "Account bijgewerkt",
|
||||||
|
"ToastAppriseUrlRequired": "Moet een Apprise URL invoeren",
|
||||||
|
"ToastAsinRequired": "ASIN is vereist",
|
||||||
"ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd",
|
"ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd",
|
||||||
|
"ToastAuthorNotFound": "Auteur \"{0}\" niet gevonden",
|
||||||
|
"ToastAuthorRemoveSuccess": "Auteur verwijderd",
|
||||||
|
"ToastAuthorSearchNotFound": "Auteur niet gevonden",
|
||||||
"ToastAuthorUpdateMerged": "Auteur samengevoegd",
|
"ToastAuthorUpdateMerged": "Auteur samengevoegd",
|
||||||
"ToastAuthorUpdateSuccess": "Auteur bijgewerkt",
|
"ToastAuthorUpdateSuccess": "Auteur bijgewerkt",
|
||||||
"ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)",
|
"ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)",
|
||||||
|
"ToastBackupAppliedSuccess": "Backup toegepast",
|
||||||
"ToastBackupCreateFailed": "Back-up maken mislukt",
|
"ToastBackupCreateFailed": "Back-up maken mislukt",
|
||||||
"ToastBackupCreateSuccess": "Back-up gemaakt",
|
"ToastBackupCreateSuccess": "Back-up gemaakt",
|
||||||
"ToastBackupDeleteFailed": "Verwijderen back-up mislukt",
|
"ToastBackupDeleteFailed": "Verwijderen back-up mislukt",
|
||||||
"ToastBackupDeleteSuccess": "Back-up verwijderd",
|
"ToastBackupDeleteSuccess": "Back-up verwijderd",
|
||||||
|
"ToastBackupInvalidMaxKeep": "Ongeldig aantal backups om bij te houden",
|
||||||
|
"ToastBackupInvalidMaxSize": "Ongeldige maximum backupgrootte",
|
||||||
"ToastBackupRestoreFailed": "Herstellen back-up mislukt",
|
"ToastBackupRestoreFailed": "Herstellen back-up mislukt",
|
||||||
"ToastBackupUploadFailed": "Uploaden back-up mislukt",
|
"ToastBackupUploadFailed": "Uploaden back-up mislukt",
|
||||||
"ToastBackupUploadSuccess": "Back-up geüpload",
|
"ToastBackupUploadSuccess": "Back-up geüpload",
|
||||||
|
"ToastBatchDeleteFailed": "Batch verwijderen mislukt",
|
||||||
|
"ToastBatchDeleteSuccess": "Batch verwijderen gelukt",
|
||||||
|
"ToastBatchQuickMatchFailed": "Batch Snel Vergelijken mislukt!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Bulk Snel Vergelijken van {0} boeken gestart!",
|
||||||
"ToastBatchUpdateFailed": "Bulk-bijwerking mislukt",
|
"ToastBatchUpdateFailed": "Bulk-bijwerking mislukt",
|
||||||
"ToastBatchUpdateSuccess": "Bulk-bijwerking gelukt",
|
"ToastBatchUpdateSuccess": "Bulk-bijwerking gelukt",
|
||||||
"ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt",
|
"ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt",
|
||||||
"ToastBookmarkCreateSuccess": "boekwijzer toegevoegd",
|
"ToastBookmarkCreateSuccess": "boekwijzer toegevoegd",
|
||||||
"ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd",
|
"ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd",
|
||||||
"ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt",
|
"ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt",
|
||||||
|
"ToastCachePurgeFailed": "Cache wissen is mislukt",
|
||||||
|
"ToastCachePurgeSuccess": "Cache succesvol verwijderd",
|
||||||
"ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten",
|
"ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten",
|
||||||
"ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben",
|
"ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben",
|
||||||
|
"ToastChaptersRemoved": "Hoofdstukken verwijderd",
|
||||||
|
"ToastChaptersUpdated": "Hoofdstukken bijgewerkt",
|
||||||
|
"ToastCollectionItemsAddFailed": "Item(s) toegevoegd aan collectie mislukt",
|
||||||
|
"ToastCollectionItemsAddSuccess": "Item(s) toegevoegd aan collectie gelukt",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie",
|
"ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie",
|
||||||
"ToastCollectionRemoveSuccess": "Collectie verwijderd",
|
"ToastCollectionRemoveSuccess": "Collectie verwijderd",
|
||||||
"ToastCollectionUpdateSuccess": "Collectie bijgewerkt",
|
"ToastCollectionUpdateSuccess": "Collectie bijgewerkt",
|
||||||
|
"ToastCoverUpdateFailed": "Cover update mislukt",
|
||||||
|
"ToastDeleteFileFailed": "Bestand verwijderen mislukt",
|
||||||
|
"ToastDeleteFileSuccess": "Bestand verwijderd",
|
||||||
|
"ToastDeviceAddFailed": "Apparaat toevoegen mislukt",
|
||||||
|
"ToastDeviceNameAlreadyExists": "Er bestaat al een e-reader met die naam",
|
||||||
|
"ToastDeviceTestEmailFailed": "Het is niet gelukt om een test-e-mail te verzenden",
|
||||||
|
"ToastDeviceTestEmailSuccess": "Test e-mail verzonden",
|
||||||
|
"ToastEmailSettingsUpdateSuccess": "Emaill intellingen bijgewerkt",
|
||||||
|
"ToastEncodeCancelFailed": "Het is niet gelukt om het coderen te annuleren",
|
||||||
|
"ToastEncodeCancelSucces": "Encode geannuleerd",
|
||||||
|
"ToastEpisodeDownloadQueueClearFailed": "Wachtrij legen mislukt",
|
||||||
|
"ToastEpisodeDownloadQueueClearSuccess": "Aflevering download-wachtrij geleegt",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} afleveringen bijgewerkt",
|
||||||
|
"ToastErrorCannotShare": "Kan niet native delen op dit apparaat",
|
||||||
|
"ToastFailedToLoadData": "Data laden mislukt",
|
||||||
|
"ToastFailedToMatch": "Match mislukt",
|
||||||
|
"ToastFailedToShare": "Delen mislukt",
|
||||||
|
"ToastFailedToUpdate": "Update mislukt",
|
||||||
|
"ToastInvalidImageUrl": "Ongeldige afbeeldings-URL",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Ongeldig maximum aantal afleveringen om te downloaden",
|
||||||
|
"ToastInvalidUrl": "Ongeldige URL",
|
||||||
"ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt",
|
"ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt",
|
||||||
|
"ToastItemDeletedFailed": "Item verwijderen mislukt",
|
||||||
|
"ToastItemDeletedSuccess": "Verwijderd item",
|
||||||
"ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt",
|
"ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt",
|
||||||
"ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt",
|
"ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt",
|
||||||
"ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid",
|
"ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid",
|
||||||
"ToastItemMarkedAsNotFinishedFailed": "Markeren als Niet Voltooid mislukt",
|
"ToastItemMarkedAsNotFinishedFailed": "Markeren als Niet Voltooid mislukt",
|
||||||
"ToastItemMarkedAsNotFinishedSuccess": "Onderdeel gemarkeerd als Niet Voltooid",
|
"ToastItemMarkedAsNotFinishedSuccess": "Onderdeel gemarkeerd als Niet Voltooid",
|
||||||
|
"ToastItemUpdateSuccess": "Item bijgewerkt",
|
||||||
"ToastLibraryCreateFailed": "Bibliotheek aanmaken mislukt",
|
"ToastLibraryCreateFailed": "Bibliotheek aanmaken mislukt",
|
||||||
"ToastLibraryCreateSuccess": "Bibliotheek \"{0}\" aangemaakt",
|
"ToastLibraryCreateSuccess": "Bibliotheek \"{0}\" aangemaakt",
|
||||||
"ToastLibraryDeleteFailed": "Bibliotheek verwijderen mislukt",
|
"ToastLibraryDeleteFailed": "Bibliotheek verwijderen mislukt",
|
||||||
@@ -683,25 +987,83 @@
|
|||||||
"ToastLibraryScanFailedToStart": "Starten scan mislukt",
|
"ToastLibraryScanFailedToStart": "Starten scan mislukt",
|
||||||
"ToastLibraryScanStarted": "Scannen bibliotheek gestart",
|
"ToastLibraryScanStarted": "Scannen bibliotheek gestart",
|
||||||
"ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt",
|
"ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt",
|
||||||
|
"ToastMatchAllAuthorsFailed": "Alle auteurs matchen mislukt",
|
||||||
|
"ToastMetadataFilesRemovedError": "Fout bij verwijderen van metadata. {0} bestanden",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "Geen metadata. {0} bestanden gevonden in bibliotheek",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Geen metadata. {0} bestanden verwijderd",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadata. {1} bestanden verwijderd",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Moet ten minste een pad hebben",
|
||||||
|
"ToastNameEmailRequired": "Naam en email zijn vereist",
|
||||||
|
"ToastNameRequired": "Naam is vereist",
|
||||||
|
"ToastNewEpisodesFound": "{0} nieuwe afleveringen gevonden",
|
||||||
|
"ToastNewUserCreatedFailed": "Account: \"{0}\" aanmaken mislukt",
|
||||||
|
"ToastNewUserCreatedSuccess": "Nieuw account aangemaakt",
|
||||||
|
"ToastNewUserLibraryError": "Moet ten minste een bibliotheek selecteren",
|
||||||
|
"ToastNewUserPasswordError": "Moet een wachtwoord hebben, enkel root gebruiker kan een leeg wachtwoord gebruiken",
|
||||||
|
"ToastNewUserTagError": "Moet ten minste een tag selecteren",
|
||||||
|
"ToastNewUserUsernameError": "Voer een gebruikersnaam in",
|
||||||
|
"ToastNoNewEpisodesFound": "Geen nieuwe afleveringen gevonden",
|
||||||
|
"ToastNoUpdatesNecessary": "Geen updates nodig",
|
||||||
|
"ToastNotificationCreateFailed": "Nieuwe melding aanmaken mislukt",
|
||||||
|
"ToastNotificationDeleteFailed": "Melding verwijderen mislukt",
|
||||||
|
"ToastNotificationFailedMaximum": "Maximum aantal pogingen moet >=0",
|
||||||
|
"ToastNotificationQueueMaximum": "Maximale meldingen wachtrij moet >=0",
|
||||||
|
"ToastNotificationSettingsUpdateSuccess": "Meldingsinstellingen bijgewerkt",
|
||||||
|
"ToastNotificationTestTriggerFailed": "Het is niet gelukt om een testmelding te activeren",
|
||||||
|
"ToastNotificationTestTriggerSuccess": "Geactiveerde testmelding",
|
||||||
|
"ToastNotificationUpdateSuccess": "Melding bijgewerkt",
|
||||||
"ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt",
|
"ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt",
|
||||||
"ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt",
|
"ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt",
|
||||||
"ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd",
|
"ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd",
|
||||||
"ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt",
|
"ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt",
|
||||||
"ToastPodcastCreateFailed": "Podcast aanmaken mislukt",
|
"ToastPodcastCreateFailed": "Podcast aanmaken mislukt",
|
||||||
"ToastPodcastCreateSuccess": "Podcast aangemaakt",
|
"ToastPodcastCreateSuccess": "Podcast aangemaakt",
|
||||||
|
"ToastPodcastGetFeedFailed": "Podcast feed ophalen mislukt",
|
||||||
|
"ToastPodcastNoEpisodesInFeed": "Geen afleveringen gevonden in RSS feed",
|
||||||
|
"ToastPodcastNoRssFeed": "Podcast heeft geen RSS feed",
|
||||||
|
"ToastProgressIsNotBeingSynced": "De voortgang wordt niet gesynchroniseerd, start het afspelen opnieuw",
|
||||||
|
"ToastProviderCreatedFailed": "Provider toevoegen mislukt",
|
||||||
|
"ToastProviderCreatedSuccess": "Nieuwe provider toegevoegd",
|
||||||
|
"ToastProviderNameAndUrlRequired": "Naam en URL vereist",
|
||||||
|
"ToastProviderRemoveSuccess": "Provider verwijderd",
|
||||||
"ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt",
|
"ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt",
|
||||||
"ToastRSSFeedCloseSuccess": "RSS-feed gesloten",
|
"ToastRSSFeedCloseSuccess": "RSS-feed gesloten",
|
||||||
|
"ToastRemoveFailed": "Verwijderen mislukt",
|
||||||
"ToastRemoveItemFromCollectionFailed": "Onderdeel verwijderen uit collectie mislukt",
|
"ToastRemoveItemFromCollectionFailed": "Onderdeel verwijderen uit collectie mislukt",
|
||||||
"ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie",
|
"ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie",
|
||||||
|
"ToastRemoveItemsWithIssuesFailed": "Verwijderen van bibliotheekitems met problemen mislukt",
|
||||||
|
"ToastRemoveItemsWithIssuesSuccess": "Bibliotheekitems met problemen verwijderd",
|
||||||
|
"ToastRenameFailed": "Hernoemen mislukt",
|
||||||
|
"ToastRescanFailed": "Opnieuw scannen mislukt voor {0}",
|
||||||
|
"ToastRescanRemoved": "Opnieuw scannen voltooid, item is verwijderd",
|
||||||
|
"ToastRescanUpToDate": "Rescan voltooid, item is up to date",
|
||||||
|
"ToastRescanUpdated": "Rescan voltooid, item is geupdated",
|
||||||
|
"ToastScanFailed": "Bibliotheek item scannen mislukt",
|
||||||
|
"ToastSelectAtLeastOneUser": "Selecteer ten minste een gebruiker",
|
||||||
"ToastSendEbookToDeviceFailed": "Ebook naar apparaat sturen mislukt",
|
"ToastSendEbookToDeviceFailed": "Ebook naar apparaat sturen mislukt",
|
||||||
"ToastSendEbookToDeviceSuccess": "Ebook verstuurd naar apparaat \"{0}\"",
|
"ToastSendEbookToDeviceSuccess": "Ebook verstuurd naar apparaat \"{0}\"",
|
||||||
"ToastSeriesUpdateFailed": "Bijwerken serie mislukt",
|
"ToastSeriesUpdateFailed": "Bijwerken serie mislukt",
|
||||||
"ToastSeriesUpdateSuccess": "Bijwerken serie gelukt",
|
"ToastSeriesUpdateSuccess": "Bijwerken serie gelukt",
|
||||||
|
"ToastServerSettingsUpdateSuccess": "Server instellingen bijgewerkt",
|
||||||
|
"ToastSessionCloseFailed": "Sessie sluiten mislukt",
|
||||||
"ToastSessionDeleteFailed": "Verwijderen sessie mislukt",
|
"ToastSessionDeleteFailed": "Verwijderen sessie mislukt",
|
||||||
"ToastSessionDeleteSuccess": "Sessie verwijderd",
|
"ToastSessionDeleteSuccess": "Sessie verwijderd",
|
||||||
|
"ToastSleepTimerDone": "Slaap timer voltooid... zZzzZz",
|
||||||
|
"ToastSlugMustChange": "Slug bevat ongeldige symbolen",
|
||||||
|
"ToastSlugRequired": "Slug is vereist",
|
||||||
"ToastSocketConnected": "Socket verbonden",
|
"ToastSocketConnected": "Socket verbonden",
|
||||||
"ToastSocketDisconnected": "Socket niet verbonden",
|
"ToastSocketDisconnected": "Socket niet verbonden",
|
||||||
"ToastSocketFailedToConnect": "Verbinding Socket mislukt",
|
"ToastSocketFailedToConnect": "Verbinding Socket mislukt",
|
||||||
|
"ToastSortingPrefixesEmptyError": "Moet ten minste 1 sorteer-prefix bevatten",
|
||||||
|
"ToastSortingPrefixesUpdateSuccess": "Sorteer prefixes geupdated ({0} items)",
|
||||||
|
"ToastTitleRequired": "Titel is vereist",
|
||||||
|
"ToastUnknownError": "Onbekende fout",
|
||||||
|
"ToastUnlinkOpenIdFailed": "Gebruiker ontkoppelen van OpenID mislukt",
|
||||||
|
"ToastUnlinkOpenIdSuccess": "Gebruiker ontkoppeld van OpenID",
|
||||||
"ToastUserDeleteFailed": "Verwijderen gebruiker mislukt",
|
"ToastUserDeleteFailed": "Verwijderen gebruiker mislukt",
|
||||||
"ToastUserDeleteSuccess": "Gebruiker verwijderd"
|
"ToastUserDeleteSuccess": "Gebruiker verwijderd",
|
||||||
|
"ToastUserPasswordChangeSuccess": "Wachtwoord succesvol gewijzigd",
|
||||||
|
"ToastUserPasswordMismatch": "Wachtwoorden komen niet overeen",
|
||||||
|
"ToastUserPasswordMustChange": "Het nieuwe wachtwoord kan niet overeenkomen met het oude wachtwoord",
|
||||||
|
"ToastUserRootRequireName": "U moet een root-gebruikersnaam invoeren"
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -64,6 +64,7 @@
|
|||||||
"ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji",
|
"ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji",
|
||||||
"ButtonQueueAddItem": "Dodaj do kolejki",
|
"ButtonQueueAddItem": "Dodaj do kolejki",
|
||||||
"ButtonQueueRemoveItem": "Usuń z kolejki",
|
"ButtonQueueRemoveItem": "Usuń z kolejki",
|
||||||
|
"ButtonQuickEmbed": "Szybkie wstawienie",
|
||||||
"ButtonQuickEmbedMetadata": "Szybkie wstawianie metadanych",
|
"ButtonQuickEmbedMetadata": "Szybkie wstawianie metadanych",
|
||||||
"ButtonQuickMatch": "Szybkie dopasowanie",
|
"ButtonQuickMatch": "Szybkie dopasowanie",
|
||||||
"ButtonReScan": "Ponowne skanowanie",
|
"ButtonReScan": "Ponowne skanowanie",
|
||||||
@@ -95,7 +96,7 @@
|
|||||||
"ButtonStartM4BEncode": "Eksportuj jako plik M4B",
|
"ButtonStartM4BEncode": "Eksportuj jako plik M4B",
|
||||||
"ButtonStartMetadataEmbed": "Osadź metadane",
|
"ButtonStartMetadataEmbed": "Osadź metadane",
|
||||||
"ButtonStats": "Statystyki",
|
"ButtonStats": "Statystyki",
|
||||||
"ButtonSubmit": "Pobierz",
|
"ButtonSubmit": "Zapisz",
|
||||||
"ButtonTest": "Test",
|
"ButtonTest": "Test",
|
||||||
"ButtonUnlinkOpenId": "Odłącz OpenID",
|
"ButtonUnlinkOpenId": "Odłącz OpenID",
|
||||||
"ButtonUpload": "Wgraj",
|
"ButtonUpload": "Wgraj",
|
||||||
@@ -138,6 +139,7 @@
|
|||||||
"HeaderFindChapters": "Wyszukaj rozdziały",
|
"HeaderFindChapters": "Wyszukaj rozdziały",
|
||||||
"HeaderIgnoredFiles": "Zignoruj pliki",
|
"HeaderIgnoredFiles": "Zignoruj pliki",
|
||||||
"HeaderItemFiles": "Pliki",
|
"HeaderItemFiles": "Pliki",
|
||||||
|
"HeaderItemMetadataUtils": "Narzędzia dla metadanych",
|
||||||
"HeaderLastListeningSession": "Ostatnia sesja słuchania",
|
"HeaderLastListeningSession": "Ostatnia sesja słuchania",
|
||||||
"HeaderLatestEpisodes": "Najnowsze odcinki",
|
"HeaderLatestEpisodes": "Najnowsze odcinki",
|
||||||
"HeaderLibraries": "Biblioteki",
|
"HeaderLibraries": "Biblioteki",
|
||||||
@@ -176,6 +178,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Usuń {0} odcinków",
|
"HeaderRemoveEpisodes": "Usuń {0} odcinków",
|
||||||
"HeaderSavedMediaProgress": "Zapisany postęp",
|
"HeaderSavedMediaProgress": "Zapisany postęp",
|
||||||
"HeaderSchedule": "Harmonogram",
|
"HeaderSchedule": "Harmonogram",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Planowanie automatycznego ściągania odcinków",
|
||||||
"HeaderScheduleLibraryScans": "Zaplanuj automatyczne skanowanie biblioteki",
|
"HeaderScheduleLibraryScans": "Zaplanuj automatyczne skanowanie biblioteki",
|
||||||
"HeaderSession": "Sesja",
|
"HeaderSession": "Sesja",
|
||||||
"HeaderSetBackupSchedule": "Ustaw harmonogram tworzenia kopii zapasowej",
|
"HeaderSetBackupSchedule": "Ustaw harmonogram tworzenia kopii zapasowej",
|
||||||
@@ -221,7 +224,11 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Wszyscy użytkownicy z wyłączeniem gości",
|
"LabelAllUsersExcludingGuests": "Wszyscy użytkownicy z wyłączeniem gości",
|
||||||
"LabelAllUsersIncludingGuests": "Wszyscy użytkownicy, łącznie z gośćmi",
|
"LabelAllUsersIncludingGuests": "Wszyscy użytkownicy, łącznie z gośćmi",
|
||||||
"LabelAlreadyInYourLibrary": "Już istnieje w twojej bibliotece",
|
"LabelAlreadyInYourLibrary": "Już istnieje w twojej bibliotece",
|
||||||
|
"LabelApiToken": "API Token",
|
||||||
"LabelAppend": "Dołącz",
|
"LabelAppend": "Dołącz",
|
||||||
|
"LabelAudioBitrate": "Audio Bitrate (np. 128k)",
|
||||||
|
"LabelAudioChannels": "Kanały dźwięku (1 lub 2)",
|
||||||
|
"LabelAudioCodec": "Kodek audio",
|
||||||
"LabelAuthor": "Autor",
|
"LabelAuthor": "Autor",
|
||||||
"LabelAuthorFirstLast": "Autor (Rosnąco)",
|
"LabelAuthorFirstLast": "Autor (Rosnąco)",
|
||||||
"LabelAuthorLastFirst": "Author (Malejąco)",
|
"LabelAuthorLastFirst": "Author (Malejąco)",
|
||||||
@@ -233,6 +240,7 @@
|
|||||||
"LabelAutoRegister": "Automatyczna rejestracja",
|
"LabelAutoRegister": "Automatyczna rejestracja",
|
||||||
"LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu",
|
"LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu",
|
||||||
"LabelBackToUser": "Powrót",
|
"LabelBackToUser": "Powrót",
|
||||||
|
"LabelBackupAudioFiles": "Kopia zapasowa plików audio",
|
||||||
"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",
|
||||||
@@ -241,15 +249,18 @@
|
|||||||
"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",
|
"LabelBitrate": "Bitrate",
|
||||||
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Książki",
|
"LabelBooks": "Książki",
|
||||||
"LabelButtonText": "Tekst przycisku",
|
"LabelButtonText": "Tekst przycisku",
|
||||||
"LabelByAuthor": "autorstwa {0}",
|
"LabelByAuthor": "autorstwa {0}",
|
||||||
"LabelChangePassword": "Zmień hasło",
|
"LabelChangePassword": "Zmień hasło",
|
||||||
"LabelChannels": "Kanały",
|
"LabelChannels": "Kanały",
|
||||||
|
"LabelChapterCount": "{0} rozdziałów",
|
||||||
"LabelChapterTitle": "Tytuł rozdziału",
|
"LabelChapterTitle": "Tytuł rozdziału",
|
||||||
"LabelChapters": "Rozdziały",
|
"LabelChapters": "Rozdziały",
|
||||||
"LabelChaptersFound": "Znalezione rozdziały",
|
"LabelChaptersFound": "Znalezione rozdziały",
|
||||||
"LabelClickForMoreInfo": "Kliknij po więcej szczegółów",
|
"LabelClickForMoreInfo": "Kliknij po więcej szczegółów",
|
||||||
|
"LabelClickToUseCurrentValue": "Kliknij by zastosować aktualną wartość",
|
||||||
"LabelClosePlayer": "Zamknij odtwarzacz",
|
"LabelClosePlayer": "Zamknij odtwarzacz",
|
||||||
"LabelCodec": "Kodek",
|
"LabelCodec": "Kodek",
|
||||||
"LabelCollapseSeries": "Podsumuj serię",
|
"LabelCollapseSeries": "Podsumuj serię",
|
||||||
@@ -299,6 +310,7 @@
|
|||||||
"LabelEmailSettingsTestAddress": "Adres testowy",
|
"LabelEmailSettingsTestAddress": "Adres testowy",
|
||||||
"LabelEmbeddedCover": "Wbudowana okładka",
|
"LabelEmbeddedCover": "Wbudowana okładka",
|
||||||
"LabelEnable": "Włącz",
|
"LabelEnable": "Włącz",
|
||||||
|
"LabelEncodingBackupLocation": "Kopia zapasowa twoich oryginalnych plików audio będzie się znajdować w:",
|
||||||
"LabelEnd": "Zakończ",
|
"LabelEnd": "Zakończ",
|
||||||
"LabelEndOfChapter": "Koniec rozdziału",
|
"LabelEndOfChapter": "Koniec rozdziału",
|
||||||
"LabelEpisode": "Odcinek",
|
"LabelEpisode": "Odcinek",
|
||||||
|
|||||||
@@ -258,12 +258,15 @@
|
|||||||
"LabelDiscFromFilename": "Disco a partir do nome do arquivo",
|
"LabelDiscFromFilename": "Disco a partir do nome do arquivo",
|
||||||
"LabelDiscFromMetadata": "Disco a partir dos metadados",
|
"LabelDiscFromMetadata": "Disco a partir dos metadados",
|
||||||
"LabelDiscover": "Descobrir",
|
"LabelDiscover": "Descobrir",
|
||||||
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download de {0} Episódios",
|
"LabelDownloadNEpisodes": "Download de {0} Episódios",
|
||||||
"LabelDuration": "Duração",
|
"LabelDuration": "Duração",
|
||||||
"LabelDurationComparisonExactMatch": "(exato)",
|
"LabelDurationComparisonExactMatch": "(exato)",
|
||||||
"LabelDurationComparisonLonger": "({0} maior)",
|
"LabelDurationComparisonLonger": "({0} maior)",
|
||||||
"LabelDurationComparisonShorter": "({0} menor)",
|
"LabelDurationComparisonShorter": "({0} menor)",
|
||||||
"LabelDurationFound": "Duração comprovada:",
|
"LabelDurationFound": "Duração comprovada:",
|
||||||
|
"LabelEbook": "Ebook",
|
||||||
|
"LabelEbooks": "Ebooks",
|
||||||
"LabelEdit": "Editar",
|
"LabelEdit": "Editar",
|
||||||
"LabelEmailSettingsFromAddress": "Remetente",
|
"LabelEmailSettingsFromAddress": "Remetente",
|
||||||
"LabelEmailSettingsRejectUnauthorized": "Rejeitar certificados não autorizados",
|
"LabelEmailSettingsRejectUnauthorized": "Rejeitar certificados não autorizados",
|
||||||
|
|||||||
+118
-3
@@ -66,6 +66,7 @@
|
|||||||
"ButtonPurgeItemsCache": "Очистить кэш элементов",
|
"ButtonPurgeItemsCache": "Очистить кэш элементов",
|
||||||
"ButtonQueueAddItem": "Добавить в очередь",
|
"ButtonQueueAddItem": "Добавить в очередь",
|
||||||
"ButtonQueueRemoveItem": "Удалить из очереди",
|
"ButtonQueueRemoveItem": "Удалить из очереди",
|
||||||
|
"ButtonQuickEmbed": "Быстрое внедрение",
|
||||||
"ButtonQuickEmbedMetadata": "Быстрое встраивание метаданных",
|
"ButtonQuickEmbedMetadata": "Быстрое встраивание метаданных",
|
||||||
"ButtonQuickMatch": "Быстрый поиск",
|
"ButtonQuickMatch": "Быстрый поиск",
|
||||||
"ButtonReScan": "Пересканировать",
|
"ButtonReScan": "Пересканировать",
|
||||||
@@ -162,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Уведомление об обновлении",
|
"HeaderNotificationUpdate": "Уведомление об обновлении",
|
||||||
"HeaderNotifications": "Уведомления",
|
"HeaderNotifications": "Уведомления",
|
||||||
"HeaderOpenIDConnectAuthentication": "Аутентификация OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Аутентификация OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Открытые сеансы прослушивания",
|
||||||
"HeaderOpenRSSFeed": "Открыть RSS-канал",
|
"HeaderOpenRSSFeed": "Открыть RSS-канал",
|
||||||
"HeaderOtherFiles": "Другие файлы",
|
"HeaderOtherFiles": "Другие файлы",
|
||||||
"HeaderPasswordAuthentication": "Аутентификация по паролю",
|
"HeaderPasswordAuthentication": "Аутентификация по паролю",
|
||||||
@@ -179,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Удалить {0} эпизодов",
|
"HeaderRemoveEpisodes": "Удалить {0} эпизодов",
|
||||||
"HeaderSavedMediaProgress": "Прогресс медиа сохранен",
|
"HeaderSavedMediaProgress": "Прогресс медиа сохранен",
|
||||||
"HeaderSchedule": "Планировщик",
|
"HeaderSchedule": "Планировщик",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Запланируйте автоматическую загрузку эпизодов",
|
||||||
"HeaderScheduleLibraryScans": "Планировщик автоматического сканирования библиотеки",
|
"HeaderScheduleLibraryScans": "Планировщик автоматического сканирования библиотеки",
|
||||||
"HeaderSession": "Сеансы",
|
"HeaderSession": "Сеансы",
|
||||||
"HeaderSetBackupSchedule": "Установить планировщик бэкапов",
|
"HeaderSetBackupSchedule": "Установить планировщик бэкапов",
|
||||||
@@ -224,7 +227,11 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Все пользователи, кроме гостей",
|
"LabelAllUsersExcludingGuests": "Все пользователи, кроме гостей",
|
||||||
"LabelAllUsersIncludingGuests": "Все пользователи, включая гостей",
|
"LabelAllUsersIncludingGuests": "Все пользователи, включая гостей",
|
||||||
"LabelAlreadyInYourLibrary": "Уже в Вашей библиотеке",
|
"LabelAlreadyInYourLibrary": "Уже в Вашей библиотеке",
|
||||||
|
"LabelApiToken": "Токен API",
|
||||||
"LabelAppend": "Добавить",
|
"LabelAppend": "Добавить",
|
||||||
|
"LabelAudioBitrate": "Битрейт (напр. 128k)",
|
||||||
|
"LabelAudioChannels": "Аудиоканалы (1 или 2)",
|
||||||
|
"LabelAudioCodec": "Аудиокодек",
|
||||||
"LabelAuthor": "Автор",
|
"LabelAuthor": "Автор",
|
||||||
"LabelAuthorFirstLast": "Автор (Имя Фамилия)",
|
"LabelAuthorFirstLast": "Автор (Имя Фамилия)",
|
||||||
"LabelAuthorLastFirst": "Автор (Фамилия, Имя)",
|
"LabelAuthorLastFirst": "Автор (Фамилия, Имя)",
|
||||||
@@ -237,6 +244,7 @@
|
|||||||
"LabelAutoRegister": "Автоматическая регистрация",
|
"LabelAutoRegister": "Автоматическая регистрация",
|
||||||
"LabelAutoRegisterDescription": "Автоматическое создание новых пользователей после входа в систему",
|
"LabelAutoRegisterDescription": "Автоматическое создание новых пользователей после входа в систему",
|
||||||
"LabelBackToUser": "Назад к пользователю",
|
"LabelBackToUser": "Назад к пользователю",
|
||||||
|
"LabelBackupAudioFiles": "Резервное копирование аудиофайлов",
|
||||||
"LabelBackupLocation": "Путь для бэкапов",
|
"LabelBackupLocation": "Путь для бэкапов",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Включить автоматическое бэкапирование",
|
"LabelBackupsEnableAutomaticBackups": "Включить автоматическое бэкапирование",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Бэкапы сохраняются в /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Бэкапы сохраняются в /metadata/backups",
|
||||||
@@ -245,15 +253,18 @@
|
|||||||
"LabelBackupsNumberToKeep": "Сохранять бэкапов",
|
"LabelBackupsNumberToKeep": "Сохранять бэкапов",
|
||||||
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
|
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
|
||||||
"LabelBitrate": "Битрейт",
|
"LabelBitrate": "Битрейт",
|
||||||
|
"LabelBonus": "Бонус",
|
||||||
"LabelBooks": "Книги",
|
"LabelBooks": "Книги",
|
||||||
"LabelButtonText": "Текст кнопки",
|
"LabelButtonText": "Текст кнопки",
|
||||||
"LabelByAuthor": "{0}",
|
"LabelByAuthor": "{0}",
|
||||||
"LabelChangePassword": "Изменить пароль",
|
"LabelChangePassword": "Изменить пароль",
|
||||||
"LabelChannels": "Каналы",
|
"LabelChannels": "Каналы",
|
||||||
|
"LabelChapterCount": "{0} Главы",
|
||||||
"LabelChapterTitle": "Название главы",
|
"LabelChapterTitle": "Название главы",
|
||||||
"LabelChapters": "Главы",
|
"LabelChapters": "Главы",
|
||||||
"LabelChaptersFound": "глав найдено",
|
"LabelChaptersFound": "глав найдено",
|
||||||
"LabelClickForMoreInfo": "Нажмите, чтобы узнать больше",
|
"LabelClickForMoreInfo": "Нажмите, чтобы узнать больше",
|
||||||
|
"LabelClickToUseCurrentValue": "Нажмите, чтобы использовать текущее значение",
|
||||||
"LabelClosePlayer": "Закрыть проигрыватель",
|
"LabelClosePlayer": "Закрыть проигрыватель",
|
||||||
"LabelCodec": "Кодек",
|
"LabelCodec": "Кодек",
|
||||||
"LabelCollapseSeries": "Свернуть серии",
|
"LabelCollapseSeries": "Свернуть серии",
|
||||||
@@ -303,12 +314,25 @@
|
|||||||
"LabelEmailSettingsTestAddress": "Тестовый адрес",
|
"LabelEmailSettingsTestAddress": "Тестовый адрес",
|
||||||
"LabelEmbeddedCover": "Встроенная обложка",
|
"LabelEmbeddedCover": "Встроенная обложка",
|
||||||
"LabelEnable": "Включить",
|
"LabelEnable": "Включить",
|
||||||
|
"LabelEncodingBackupLocation": "Резервная копия ваших оригинальных аудиофайлов будет сохранена в:",
|
||||||
|
"LabelEncodingChaptersNotEmbedded": "Главы не встраиваются в многодорожечные аудиокниги.",
|
||||||
|
"LabelEncodingClearItemCache": "Обязательно периодически очищайте кэш элементов.",
|
||||||
|
"LabelEncodingFinishedM4B": "Готовый M4B будет помещен в вашу папку с аудиокнигами по адресу:",
|
||||||
|
"LabelEncodingInfoEmbedded": "Метаданные будут встроены в звуковые дорожки внутри папки вашей аудиокниги.",
|
||||||
|
"LabelEncodingStartedNavigation": "Как только задача будет запущена, вы сможете перейти с этой страницы.",
|
||||||
|
"LabelEncodingTimeWarning": "Кодирование может занять до 30 минут.",
|
||||||
|
"LabelEncodingWarningAdvancedSettings": "Предупреждение: Не обновляйте эти настройки, если вы не знакомы с параметрами кодировки ffmpeg.",
|
||||||
|
"LabelEncodingWatcherDisabled": "Если у вас отключено наблюдение за папкой, вам нужно будет повторно пересканировать эту аудиокнигу.",
|
||||||
"LabelEnd": "Конец",
|
"LabelEnd": "Конец",
|
||||||
"LabelEndOfChapter": "Конец главы",
|
"LabelEndOfChapter": "Конец главы",
|
||||||
"LabelEpisode": "Эпизод",
|
"LabelEpisode": "Эпизод",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Эпизод, не связанный с RSS-каналом",
|
||||||
|
"LabelEpisodeNumber": "Эпизод #{0}",
|
||||||
"LabelEpisodeTitle": "Имя эпизода",
|
"LabelEpisodeTitle": "Имя эпизода",
|
||||||
"LabelEpisodeType": "Тип эпизода",
|
"LabelEpisodeType": "Тип эпизода",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "URL-адрес эпизода из RSS-ленты",
|
||||||
"LabelEpisodes": "Эпизодов",
|
"LabelEpisodes": "Эпизодов",
|
||||||
|
"LabelEpisodic": "Эпизодический",
|
||||||
"LabelExample": "Пример",
|
"LabelExample": "Пример",
|
||||||
"LabelExpandSeries": "Развернуть серию",
|
"LabelExpandSeries": "Развернуть серию",
|
||||||
"LabelExpandSubSeries": "Развернуть подсерию",
|
"LabelExpandSubSeries": "Развернуть подсерию",
|
||||||
@@ -336,12 +360,13 @@
|
|||||||
"LabelFontScale": "Масштаб шрифта",
|
"LabelFontScale": "Масштаб шрифта",
|
||||||
"LabelFontStrikethrough": "Зачеркнутый",
|
"LabelFontStrikethrough": "Зачеркнутый",
|
||||||
"LabelFormat": "Формат",
|
"LabelFormat": "Формат",
|
||||||
|
"LabelFull": "Полный",
|
||||||
"LabelGenre": "Жанр",
|
"LabelGenre": "Жанр",
|
||||||
"LabelGenres": "Жанры",
|
"LabelGenres": "Жанры",
|
||||||
"LabelHardDeleteFile": "Жесткое удаление файла",
|
"LabelHardDeleteFile": "Жесткое удаление файла",
|
||||||
"LabelHasEbook": "Есть e-книга",
|
"LabelHasEbook": "Есть e-книга",
|
||||||
"LabelHasSupplementaryEbook": "Есть дополнительная e-книга",
|
"LabelHasSupplementaryEbook": "Есть дополнительная e-книга",
|
||||||
"LabelHideSubtitles": "Скрыть субтитры",
|
"LabelHideSubtitles": "Скрыть серии",
|
||||||
"LabelHighestPriority": "Наивысший приоритет",
|
"LabelHighestPriority": "Наивысший приоритет",
|
||||||
"LabelHost": "Хост",
|
"LabelHost": "Хост",
|
||||||
"LabelHour": "Часы",
|
"LabelHour": "Часы",
|
||||||
@@ -391,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "Самый низкий приоритет",
|
"LabelLowestPriority": "Самый низкий приоритет",
|
||||||
"LabelMatchExistingUsersBy": "Сопоставление существующих пользователей по",
|
"LabelMatchExistingUsersBy": "Сопоставление существующих пользователей по",
|
||||||
"LabelMatchExistingUsersByDescription": "Используется для подключения существующих пользователей. После подключения пользователям будет присвоен уникальный идентификатор от поставщика единого входа",
|
"LabelMatchExistingUsersByDescription": "Используется для подключения существующих пользователей. После подключения пользователям будет присвоен уникальный идентификатор от поставщика единого входа",
|
||||||
|
"LabelMaxEpisodesToDownload": "Максимальное количество эпизодов для загрузки. Используйте 0 для неограниченного количества.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Максимальное количество новых эпизодов для загрузки за одну проверку",
|
||||||
|
"LabelMaxEpisodesToKeep": "Максимальное количество сохраняемых эпизодов",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "Значение 0 не устанавливает максимального ограничения. После автоматической загрузки нового эпизода самый старый эпизод будет удален, если у вас более X эпизодов. При этом будет удален только 1 эпизод за каждую новую загрузку.",
|
||||||
"LabelMediaPlayer": "Медиа проигрыватель",
|
"LabelMediaPlayer": "Медиа проигрыватель",
|
||||||
"LabelMediaType": "Тип медиа",
|
"LabelMediaType": "Тип медиа",
|
||||||
"LabelMetaTag": "Мета тег",
|
"LabelMetaTag": "Мета тег",
|
||||||
@@ -436,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.",
|
"LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.",
|
||||||
"LabelOpenRSSFeed": "Открыть RSS-канал",
|
"LabelOpenRSSFeed": "Открыть RSS-канал",
|
||||||
"LabelOverwrite": "Перезаписать",
|
"LabelOverwrite": "Перезаписать",
|
||||||
|
"LabelPaginationPageXOfY": "Страница {0} из {1}",
|
||||||
"LabelPassword": "Пароль",
|
"LabelPassword": "Пароль",
|
||||||
"LabelPath": "Путь",
|
"LabelPath": "Путь",
|
||||||
"LabelPermanent": "Постоянный",
|
"LabelPermanent": "Постоянный",
|
||||||
"LabelPermissionsAccessAllLibraries": "Есть доступ ко всем библиотекам",
|
"LabelPermissionsAccessAllLibraries": "Есть доступ ко всем библиотекам",
|
||||||
"LabelPermissionsAccessAllTags": "Есть доступ ко всем тегам",
|
"LabelPermissionsAccessAllTags": "Есть доступ ко всем тегам",
|
||||||
"LabelPermissionsAccessExplicitContent": "Есть доступ к явному содержимому",
|
"LabelPermissionsAccessExplicitContent": "Есть доступ к явному содержимому",
|
||||||
|
"LabelPermissionsCreateEreader": "Можно создать читалку",
|
||||||
"LabelPermissionsDelete": "Может удалять",
|
"LabelPermissionsDelete": "Может удалять",
|
||||||
"LabelPermissionsDownload": "Может скачивать",
|
"LabelPermissionsDownload": "Может скачивать",
|
||||||
"LabelPermissionsUpdate": "Может обновлять",
|
"LabelPermissionsUpdate": "Может обновлять",
|
||||||
@@ -465,6 +496,8 @@
|
|||||||
"LabelPubDate": "Дата публикации",
|
"LabelPubDate": "Дата публикации",
|
||||||
"LabelPublishYear": "Год публикации",
|
"LabelPublishYear": "Год публикации",
|
||||||
"LabelPublishedDate": "Опубликовано {0}",
|
"LabelPublishedDate": "Опубликовано {0}",
|
||||||
|
"LabelPublishedDecade": "Декада публикации",
|
||||||
|
"LabelPublishedDecades": "Декады публикации",
|
||||||
"LabelPublisher": "Издатель",
|
"LabelPublisher": "Издатель",
|
||||||
"LabelPublishers": "Издатели",
|
"LabelPublishers": "Издатели",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "Пользовательский Email владельца",
|
"LabelRSSFeedCustomOwnerEmail": "Пользовательский Email владельца",
|
||||||
@@ -484,21 +517,28 @@
|
|||||||
"LabelRedo": "Повторить",
|
"LabelRedo": "Повторить",
|
||||||
"LabelRegion": "Регион",
|
"LabelRegion": "Регион",
|
||||||
"LabelReleaseDate": "Дата выхода",
|
"LabelReleaseDate": "Дата выхода",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Удалите все файлы metadata.abs",
|
||||||
|
"LabelRemoveAllMetadataJson": "Удалите все файлы metadata.json",
|
||||||
"LabelRemoveCover": "Удалить обложку",
|
"LabelRemoveCover": "Удалить обложку",
|
||||||
|
"LabelRemoveMetadataFile": "Удаление файлов метаданных в папках элементов библиотеки",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Удалите все файлы metadata.json и metadata.abs из ваших папок {0}.",
|
||||||
"LabelRowsPerPage": "Строк на странице",
|
"LabelRowsPerPage": "Строк на странице",
|
||||||
"LabelSearchTerm": "Поисковый запрос",
|
"LabelSearchTerm": "Поисковый запрос",
|
||||||
"LabelSearchTitle": "Поиск по названию",
|
"LabelSearchTitle": "Поиск по названию",
|
||||||
"LabelSearchTitleOrASIN": "Поиск по названию или ASIN",
|
"LabelSearchTitleOrASIN": "Поиск по названию или ASIN",
|
||||||
"LabelSeason": "Сезон",
|
"LabelSeason": "Сезон",
|
||||||
|
"LabelSeasonNumber": "Сезон #{0}",
|
||||||
"LabelSelectAll": "Выбрать все",
|
"LabelSelectAll": "Выбрать все",
|
||||||
"LabelSelectAllEpisodes": "Выбрать все эпизоды",
|
"LabelSelectAllEpisodes": "Выбрать все эпизоды",
|
||||||
"LabelSelectEpisodesShowing": "Выберите {0} эпизодов для показа",
|
"LabelSelectEpisodesShowing": "Выберите {0} эпизодов для показа",
|
||||||
"LabelSelectUsers": "Выбор пользователей",
|
"LabelSelectUsers": "Выбор пользователей",
|
||||||
"LabelSendEbookToDevice": "Отправить e-книгу в...",
|
"LabelSendEbookToDevice": "Отправить e-книгу в...",
|
||||||
"LabelSequence": "Последовательность",
|
"LabelSequence": "Последовательность",
|
||||||
|
"LabelSerial": "Серийный",
|
||||||
"LabelSeries": "Серия",
|
"LabelSeries": "Серия",
|
||||||
"LabelSeriesName": "Имя серии",
|
"LabelSeriesName": "Имя серии",
|
||||||
"LabelSeriesProgress": "Прогресс серии",
|
"LabelSeriesProgress": "Прогресс серии",
|
||||||
|
"LabelServerLogLevel": "Уровень журнала сервера",
|
||||||
"LabelServerYearReview": "Итоги года всего сервера ({0})",
|
"LabelServerYearReview": "Итоги года всего сервера ({0})",
|
||||||
"LabelSetEbookAsPrimary": "Установить как основную",
|
"LabelSetEbookAsPrimary": "Установить как основную",
|
||||||
"LabelSetEbookAsSupplementary": "Установить как дополнительную",
|
"LabelSetEbookAsSupplementary": "Установить как дополнительную",
|
||||||
@@ -523,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Серии, в которых всего одна книга, будут скрыты со страницы серий и полок домашней страницы.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Серии, в которых всего одна книга, будут скрыты со страницы серий и полок домашней страницы.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Вид книжной полки на Домашней странице",
|
"LabelSettingsHomePageBookshelfView": "Вид книжной полки на Домашней странице",
|
||||||
"LabelSettingsLibraryBookshelfView": "Вид книжной полки в Библиотеке",
|
"LabelSettingsLibraryBookshelfView": "Вид книжной полки в Библиотеке",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Процент выполнения больше, чем",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Оставшееся время составляет менее (секунд)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Отметьте мультимедийный элемент как законченный, когда",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропустить предыдущие книги в \"Продолжить серию\"",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропустить предыдущие книги в \"Продолжить серию\"",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "На домашней странице \"Продолжить серию\" отображается первая книга, не начатая в серии, в которой закончена хотя бы одна книга и нет начатых книг. При включении этого параметра серия будет продолжена с самой последней завершенной книги, а не с первой, которая не начата.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "На домашней странице \"Продолжить серию\" отображается первая книга, не начатая в серии, в которой закончена хотя бы одна книга и нет начатых книг. При включении этого параметра серия будет продолжена с самой последней завершенной книги, а не с первой, которая не начата.",
|
||||||
"LabelSettingsParseSubtitles": "Разбор подзаголовков",
|
"LabelSettingsParseSubtitles": "Разбор подзаголовков",
|
||||||
@@ -545,7 +588,7 @@
|
|||||||
"LabelShareURL": "Общедоступный URL",
|
"LabelShareURL": "Общедоступный URL",
|
||||||
"LabelShowAll": "Показать все",
|
"LabelShowAll": "Показать все",
|
||||||
"LabelShowSeconds": "Отображать секунды",
|
"LabelShowSeconds": "Отображать секунды",
|
||||||
"LabelShowSubtitles": "Показать субтитры",
|
"LabelShowSubtitles": "Показать серии",
|
||||||
"LabelSize": "Размер",
|
"LabelSize": "Размер",
|
||||||
"LabelSleepTimer": "Таймер сна",
|
"LabelSleepTimer": "Таймер сна",
|
||||||
"LabelSlug": "Слизень",
|
"LabelSlug": "Слизень",
|
||||||
@@ -587,13 +630,15 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} минут",
|
"LabelTimeDurationXMinutes": "{0} минут",
|
||||||
"LabelTimeDurationXSeconds": "{0} секунд",
|
"LabelTimeDurationXSeconds": "{0} секунд",
|
||||||
"LabelTimeInMinutes": "Время в минутах",
|
"LabelTimeInMinutes": "Время в минутах",
|
||||||
|
"LabelTimeLeft": "{0} осталось",
|
||||||
"LabelTimeListened": "Время прослушивания",
|
"LabelTimeListened": "Время прослушивания",
|
||||||
"LabelTimeListenedToday": "Время прослушивания сегодня",
|
"LabelTimeListenedToday": "Время прослушивания сегодня",
|
||||||
"LabelTimeRemaining": "{0} осталось",
|
"LabelTimeRemaining": "{0} осталось",
|
||||||
"LabelTimeToShift": "Время смещения в сек.",
|
"LabelTimeToShift": "Время смещения в секундах",
|
||||||
"LabelTitle": "Название",
|
"LabelTitle": "Название",
|
||||||
"LabelToolsEmbedMetadata": "Встроить метаданные",
|
"LabelToolsEmbedMetadata": "Встроить метаданные",
|
||||||
"LabelToolsEmbedMetadataDescription": "Встроить метаданные в аудио файлы, включая обложку и главы.",
|
"LabelToolsEmbedMetadataDescription": "Встроить метаданные в аудио файлы, включая обложку и главы.",
|
||||||
|
"LabelToolsM4bEncoder": "Кодировщик M4B",
|
||||||
"LabelToolsMakeM4b": "Создать M4B файл аудиокниги",
|
"LabelToolsMakeM4b": "Создать M4B файл аудиокниги",
|
||||||
"LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.",
|
"LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.",
|
||||||
"LabelToolsSplitM4b": "Разделить M4B на MP3 файлы",
|
"LabelToolsSplitM4b": "Разделить M4B на MP3 файлы",
|
||||||
@@ -606,6 +651,7 @@
|
|||||||
"LabelTracksMultiTrack": "Мультитрек",
|
"LabelTracksMultiTrack": "Мультитрек",
|
||||||
"LabelTracksNone": "Нет треков",
|
"LabelTracksNone": "Нет треков",
|
||||||
"LabelTracksSingleTrack": "Один трек",
|
"LabelTracksSingleTrack": "Один трек",
|
||||||
|
"LabelTrailer": "Трейлер",
|
||||||
"LabelType": "Тип",
|
"LabelType": "Тип",
|
||||||
"LabelUnabridged": "Полное издание",
|
"LabelUnabridged": "Полное издание",
|
||||||
"LabelUndo": "Отменить",
|
"LabelUndo": "Отменить",
|
||||||
@@ -617,10 +663,13 @@
|
|||||||
"LabelUpdateDetailsHelp": "Позволяет перезаписывать текущие подробности для выбранных книг если будут найдены",
|
"LabelUpdateDetailsHelp": "Позволяет перезаписывать текущие подробности для выбранных книг если будут найдены",
|
||||||
"LabelUpdatedAt": "Обновлено в",
|
"LabelUpdatedAt": "Обновлено в",
|
||||||
"LabelUploaderDragAndDrop": "Перетащите файлы или каталоги",
|
"LabelUploaderDragAndDrop": "Перетащите файлы или каталоги",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Перетаскивание файлов",
|
||||||
"LabelUploaderDropFiles": "Перетащите файлы",
|
"LabelUploaderDropFiles": "Перетащите файлы",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Автоматическое извлечение названия, автора и серии",
|
"LabelUploaderItemFetchMetadataHelp": "Автоматическое извлечение названия, автора и серии",
|
||||||
|
"LabelUseAdvancedOptions": "Используйте расширенные опции",
|
||||||
"LabelUseChapterTrack": "Показывать время главы",
|
"LabelUseChapterTrack": "Показывать время главы",
|
||||||
"LabelUseFullTrack": "Показывать время книги",
|
"LabelUseFullTrack": "Показывать время книги",
|
||||||
|
"LabelUseZeroForUnlimited": "Используйте 0 для неограниченного количества",
|
||||||
"LabelUser": "Пользователь",
|
"LabelUser": "Пользователь",
|
||||||
"LabelUsername": "Имя пользователя",
|
"LabelUsername": "Имя пользователя",
|
||||||
"LabelValue": "Значение",
|
"LabelValue": "Значение",
|
||||||
@@ -667,6 +716,7 @@
|
|||||||
"MessageConfirmDeleteMetadataProvider": "Вы уверены, что хотите удалить пользовательский поставщик метаданных \"{0}\"?",
|
"MessageConfirmDeleteMetadataProvider": "Вы уверены, что хотите удалить пользовательский поставщик метаданных \"{0}\"?",
|
||||||
"MessageConfirmDeleteNotification": "Вы уверены, что хотите удалить это уведомление?",
|
"MessageConfirmDeleteNotification": "Вы уверены, что хотите удалить это уведомление?",
|
||||||
"MessageConfirmDeleteSession": "Вы уверены, что хотите удалить этот сеанс?",
|
"MessageConfirmDeleteSession": "Вы уверены, что хотите удалить этот сеанс?",
|
||||||
|
"MessageConfirmEmbedMetadataInAudioFiles": "Вы уверены, что хотите вставить метаданные в {0} аудиофайлов?",
|
||||||
"MessageConfirmForceReScan": "Вы уверены, что хотите принудительно выполнить повторное сканирование?",
|
"MessageConfirmForceReScan": "Вы уверены, что хотите принудительно выполнить повторное сканирование?",
|
||||||
"MessageConfirmMarkAllEpisodesFinished": "Вы уверены, что хотите отметить все эпизоды как завершенные?",
|
"MessageConfirmMarkAllEpisodesFinished": "Вы уверены, что хотите отметить все эпизоды как завершенные?",
|
||||||
"MessageConfirmMarkAllEpisodesNotFinished": "Вы уверены, что хотите отметить все эпизоды как не завершенные?",
|
"MessageConfirmMarkAllEpisodesNotFinished": "Вы уверены, что хотите отметить все эпизоды как не завершенные?",
|
||||||
@@ -678,6 +728,7 @@
|
|||||||
"MessageConfirmPurgeCache": "Очистка кэша удалит весь каталог в <code>/metadata/cache</code>. <br /><br />Вы уверены, что хотите удалить каталог кэша?",
|
"MessageConfirmPurgeCache": "Очистка кэша удалит весь каталог в <code>/metadata/cache</code>. <br /><br />Вы уверены, что хотите удалить каталог кэша?",
|
||||||
"MessageConfirmPurgeItemsCache": "Очистка кэша элементов удалит весь каталог в <code>/metadata/cache/items</code>.<br />Вы уверены?",
|
"MessageConfirmPurgeItemsCache": "Очистка кэша элементов удалит весь каталог в <code>/metadata/cache/items</code>.<br />Вы уверены?",
|
||||||
"MessageConfirmQuickEmbed": "Предупреждение! Быстрое встраивание не позволяет создавать резервные копии аудиофайлов. Убедитесь, что у вас есть резервная копия аудиофайлов. <br><br>Хотите продолжить?",
|
"MessageConfirmQuickEmbed": "Предупреждение! Быстрое встраивание не позволяет создавать резервные копии аудиофайлов. Убедитесь, что у вас есть резервная копия аудиофайлов. <br><br>Хотите продолжить?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "При обнаружении совпадений информация о эпизодах быстрого поиска будет перезаписана. Будут обновлены только несопоставимые эпизоды. Вы уверены?",
|
||||||
"MessageConfirmReScanLibraryItems": "Вы уверены, что хотите пересканировать {0} элементов?",
|
"MessageConfirmReScanLibraryItems": "Вы уверены, что хотите пересканировать {0} элементов?",
|
||||||
"MessageConfirmRemoveAllChapters": "Вы уверены, что хотите удалить все главы?",
|
"MessageConfirmRemoveAllChapters": "Вы уверены, что хотите удалить все главы?",
|
||||||
"MessageConfirmRemoveAuthor": "Вы уверены, что хотите удалить автора \"{0}\"?",
|
"MessageConfirmRemoveAuthor": "Вы уверены, что хотите удалить автора \"{0}\"?",
|
||||||
@@ -685,6 +736,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "Вы уверены, что хотите удалить эпизод \"{0}\"?",
|
"MessageConfirmRemoveEpisode": "Вы уверены, что хотите удалить эпизод \"{0}\"?",
|
||||||
"MessageConfirmRemoveEpisodes": "Вы уверены, что хотите удалить {0} эпизодов?",
|
"MessageConfirmRemoveEpisodes": "Вы уверены, что хотите удалить {0} эпизодов?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Вы уверены, что хотите удалить {0} сеансов прослушивания?",
|
"MessageConfirmRemoveListeningSessions": "Вы уверены, что хотите удалить {0} сеансов прослушивания?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Вы уверены, что хотите удалить все файлы metadata. {0} файлов из папок элементов вашей библиотеки?",
|
||||||
"MessageConfirmRemoveNarrator": "Вы уверены, что хотите удалить чтеца \"{0}\"?",
|
"MessageConfirmRemoveNarrator": "Вы уверены, что хотите удалить чтеца \"{0}\"?",
|
||||||
"MessageConfirmRemovePlaylist": "Вы уверены, что хотите удалить плейлист \"{0}\"?",
|
"MessageConfirmRemovePlaylist": "Вы уверены, что хотите удалить плейлист \"{0}\"?",
|
||||||
"MessageConfirmRenameGenre": "Вы уверены, что хотите переименовать жанр \"{0}\" в \"{1}\" для всех элементов?",
|
"MessageConfirmRenameGenre": "Вы уверены, что хотите переименовать жанр \"{0}\" в \"{1}\" для всех элементов?",
|
||||||
@@ -700,6 +752,7 @@
|
|||||||
"MessageDragFilesIntoTrackOrder": "Перетащите файлы для исправления порядка треков",
|
"MessageDragFilesIntoTrackOrder": "Перетащите файлы для исправления порядка треков",
|
||||||
"MessageEmbedFailed": "Вставка не удалась!",
|
"MessageEmbedFailed": "Вставка не удалась!",
|
||||||
"MessageEmbedFinished": "Встраивание завершено!",
|
"MessageEmbedFinished": "Встраивание завершено!",
|
||||||
|
"MessageEmbedQueue": "Поставлен в очередь для внедрения метаданных ({0} в очереди)",
|
||||||
"MessageEpisodesQueuedForDownload": "{0} Эпизод(ов) запланировано для закачки",
|
"MessageEpisodesQueuedForDownload": "{0} Эпизод(ов) запланировано для закачки",
|
||||||
"MessageEreaderDevices": "Чтобы обеспечить доставку электронных книг, вам может потребоваться добавить указанный выше адрес электронной почты в качестве действительного отправителя для каждого устройства, перечисленного ниже.",
|
"MessageEreaderDevices": "Чтобы обеспечить доставку электронных книг, вам может потребоваться добавить указанный выше адрес электронной почты в качестве действительного отправителя для каждого устройства, перечисленного ниже.",
|
||||||
"MessageFeedURLWillBe": "URL канала будет {0}",
|
"MessageFeedURLWillBe": "URL канала будет {0}",
|
||||||
@@ -744,6 +797,7 @@
|
|||||||
"MessageNoLogs": "Нет логов",
|
"MessageNoLogs": "Нет логов",
|
||||||
"MessageNoMediaProgress": "Нет прогресса медиа",
|
"MessageNoMediaProgress": "Нет прогресса медиа",
|
||||||
"MessageNoNotifications": "Нет уведомлений",
|
"MessageNoNotifications": "Нет уведомлений",
|
||||||
|
"MessageNoPodcastFeed": "Недопустимый подкаст: Нет канала",
|
||||||
"MessageNoPodcastsFound": "Подкасты не найдены",
|
"MessageNoPodcastsFound": "Подкасты не найдены",
|
||||||
"MessageNoResults": "Нет результатов",
|
"MessageNoResults": "Нет результатов",
|
||||||
"MessageNoSearchResultsFor": "Нет результатов поиска для \"{0}\"",
|
"MessageNoSearchResultsFor": "Нет результатов поиска для \"{0}\"",
|
||||||
@@ -760,6 +814,10 @@
|
|||||||
"MessagePlaylistCreateFromCollection": "Создать плейлист из коллекции",
|
"MessagePlaylistCreateFromCollection": "Создать плейлист из коллекции",
|
||||||
"MessagePleaseWait": "Пожалуйста подождите...",
|
"MessagePleaseWait": "Пожалуйста подождите...",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не имеет URL-адреса RSS-канала, который можно использовать для поиска",
|
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не имеет URL-адреса RSS-канала, который можно использовать для поиска",
|
||||||
|
"MessagePodcastSearchField": "Введите поисковый запрос или URL-адрес RSS-канала",
|
||||||
|
"MessageQuickEmbedInProgress": "Быстрое внедрение в процессе выполнения",
|
||||||
|
"MessageQuickEmbedQueue": "Поставлен в очередь для быстрого внедрения ({0} в очереди)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Быстрое сопоставление всех эпизодов",
|
||||||
"MessageQuickMatchDescription": "Заполняет пустые детали элемента и обложку первым результатом поиска из «{0}». Не перезаписывает сведения, если не включен параметр сервера 'Предпочитать метаданные поиска'.",
|
"MessageQuickMatchDescription": "Заполняет пустые детали элемента и обложку первым результатом поиска из «{0}». Не перезаписывает сведения, если не включен параметр сервера 'Предпочитать метаданные поиска'.",
|
||||||
"MessageRemoveChapter": "Удалить главу",
|
"MessageRemoveChapter": "Удалить главу",
|
||||||
"MessageRemoveEpisodes": "Удалить {0} эпизод(ов)",
|
"MessageRemoveEpisodes": "Удалить {0} эпизод(ов)",
|
||||||
@@ -777,6 +835,41 @@
|
|||||||
"MessageShareExpiresIn": "Срок действия истекает через {0}",
|
"MessageShareExpiresIn": "Срок действия истекает через {0}",
|
||||||
"MessageShareURLWillBe": "URL-адрес общего доступа будет <strong>{0}</strong>",
|
"MessageShareURLWillBe": "URL-адрес общего доступа будет <strong>{0}</strong>",
|
||||||
"MessageStartPlaybackAtTime": "Начать воспроизведение для \"{0}\" с {1}?",
|
"MessageStartPlaybackAtTime": "Начать воспроизведение для \"{0}\" с {1}?",
|
||||||
|
"MessageTaskAudioFileNotWritable": "Аудиофайл \"{0}\" недоступен для записи",
|
||||||
|
"MessageTaskCanceledByUser": "Задание отменено пользователем",
|
||||||
|
"MessageTaskDownloadingEpisodeDescription": "Загрузка эпизода \"{0}\"",
|
||||||
|
"MessageTaskEmbeddingMetadata": "Внедрение метаданных",
|
||||||
|
"MessageTaskEmbeddingMetadataDescription": "Встраивание метаданных в аудиокнигу \"{0}\"",
|
||||||
|
"MessageTaskEncodingM4b": "Кодировка M4B",
|
||||||
|
"MessageTaskEncodingM4bDescription": "Кодирование аудиокниги \"{0}\" в один файл формата m4b",
|
||||||
|
"MessageTaskFailed": "Неудачный",
|
||||||
|
"MessageTaskFailedToBackupAudioFile": "Не удалось создать резервную копию аудиофайла \"{0}\"",
|
||||||
|
"MessageTaskFailedToCreateCacheDirectory": "Не удалось создать каталог кэша",
|
||||||
|
"MessageTaskFailedToEmbedMetadataInFile": "Не удалось вставить метаданные в файл \"{0}\"",
|
||||||
|
"MessageTaskFailedToMergeAudioFiles": "Не удалось объединить аудиофайлы",
|
||||||
|
"MessageTaskFailedToMoveM4bFile": "Не удалось переместить файл m4b",
|
||||||
|
"MessageTaskFailedToWriteMetadataFile": "Не удалось записать файл метаданных",
|
||||||
|
"MessageTaskMatchingBooksInLibrary": "Сопоставление книг в библиотеке \"{0}\"",
|
||||||
|
"MessageTaskNoFilesToScan": "Нет файлов для сканирования",
|
||||||
|
"MessageTaskOpmlImport": "Импорт OPML",
|
||||||
|
"MessageTaskOpmlImportDescription": "Создание подкастов из {0} RSS-каналов",
|
||||||
|
"MessageTaskOpmlImportFeed": "Канал импорта OPML",
|
||||||
|
"MessageTaskOpmlImportFeedDescription": "Импорт RSS-канала \"{0}\"",
|
||||||
|
"MessageTaskOpmlImportFeedFailed": "Не удалось получить ленту подкаста",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastDescription": "Создание подкаста \"{0}\"",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastExists": "Подкаст уже существует по адресу",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastFailed": "Не удалось создать подкаст",
|
||||||
|
"MessageTaskOpmlImportFinished": "Добавлено {0} подкастов",
|
||||||
|
"MessageTaskOpmlParseFailed": "Не удалось разобрать OPML-файл",
|
||||||
|
"MessageTaskOpmlParseFastFail": "Недопустимый тег <opml> файла OPML не найден ИЛИ тег <outline> не найден",
|
||||||
|
"MessageTaskOpmlParseNoneFound": "В OPML-файле не найдено ни одного канала",
|
||||||
|
"MessageTaskScanItemsAdded": "{0} добавлено",
|
||||||
|
"MessageTaskScanItemsMissing": "{0} отсутствует",
|
||||||
|
"MessageTaskScanItemsUpdated": "{0} обновлено",
|
||||||
|
"MessageTaskScanNoChangesNeeded": "Никаких изменений не требуется",
|
||||||
|
"MessageTaskScanningFileChanges": "Проверка изменений файлов в \"{0}\"",
|
||||||
|
"MessageTaskScanningLibrary": "Сканирование библиотеки \"{0}\"",
|
||||||
|
"MessageTaskTargetDirectoryNotWritable": "Целевой каталог недоступен для записи",
|
||||||
"MessageThinking": "Думаю...",
|
"MessageThinking": "Думаю...",
|
||||||
"MessageUploaderItemFailed": "Не удалось загрузить",
|
"MessageUploaderItemFailed": "Не удалось загрузить",
|
||||||
"MessageUploaderItemSuccess": "Успешно загружено!",
|
"MessageUploaderItemSuccess": "Успешно загружено!",
|
||||||
@@ -794,6 +887,10 @@
|
|||||||
"NoteUploaderFoldersWithMediaFiles": "Папки с медиафайлами будут обрабатываться как отдельные элементы библиотеки.",
|
"NoteUploaderFoldersWithMediaFiles": "Папки с медиафайлами будут обрабатываться как отдельные элементы библиотеки.",
|
||||||
"NoteUploaderOnlyAudioFiles": "Если загружать только аудиофайлы, то каждый аудиофайл будет обрабатываться как отдельная аудиокнига.",
|
"NoteUploaderOnlyAudioFiles": "Если загружать только аудиофайлы, то каждый аудиофайл будет обрабатываться как отдельная аудиокнига.",
|
||||||
"NoteUploaderUnsupportedFiles": "Неподдерживаемые файлы игнорируются. При выборе или удалении папки другие файлы, не находящиеся в папке элемента, игнорируются.",
|
"NoteUploaderUnsupportedFiles": "Неподдерживаемые файлы игнорируются. При выборе или удалении папки другие файлы, не находящиеся в папке элемента, игнорируются.",
|
||||||
|
"NotificationOnBackupCompletedDescription": "Запускается при завершении резервного копирования",
|
||||||
|
"NotificationOnBackupFailedDescription": "Срабатывает при сбое резервного копирования",
|
||||||
|
"NotificationOnEpisodeDownloadedDescription": "Запускается при автоматической загрузке эпизода подкаста",
|
||||||
|
"NotificationOnTestDescription": "Событие для тестирования системы оповещения",
|
||||||
"PlaceholderNewCollection": "Новое имя коллекции",
|
"PlaceholderNewCollection": "Новое имя коллекции",
|
||||||
"PlaceholderNewFolderPath": "Путь к новой папке",
|
"PlaceholderNewFolderPath": "Путь к новой папке",
|
||||||
"PlaceholderNewPlaylist": "Новое название плейлиста",
|
"PlaceholderNewPlaylist": "Новое название плейлиста",
|
||||||
@@ -819,6 +916,7 @@
|
|||||||
"StatsYearInReview": "ИТОГИ ГОДА",
|
"StatsYearInReview": "ИТОГИ ГОДА",
|
||||||
"ToastAccountUpdateSuccess": "Учетная запись обновлена",
|
"ToastAccountUpdateSuccess": "Учетная запись обновлена",
|
||||||
"ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise",
|
"ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise",
|
||||||
|
"ToastAsinRequired": "Требуется ASIN",
|
||||||
"ToastAuthorImageRemoveSuccess": "Изображение автора удалено",
|
"ToastAuthorImageRemoveSuccess": "Изображение автора удалено",
|
||||||
"ToastAuthorNotFound": "Автор \"{0}\" не найден",
|
"ToastAuthorNotFound": "Автор \"{0}\" не найден",
|
||||||
"ToastAuthorRemoveSuccess": "Автор удален",
|
"ToastAuthorRemoveSuccess": "Автор удален",
|
||||||
@@ -838,6 +936,8 @@
|
|||||||
"ToastBackupUploadSuccess": "Бэкап загружен",
|
"ToastBackupUploadSuccess": "Бэкап загружен",
|
||||||
"ToastBatchDeleteFailed": "Не удалось выполнить пакетное удаление",
|
"ToastBatchDeleteFailed": "Не удалось выполнить пакетное удаление",
|
||||||
"ToastBatchDeleteSuccess": "Успешное пакетное удаление",
|
"ToastBatchDeleteSuccess": "Успешное пакетное удаление",
|
||||||
|
"ToastBatchQuickMatchFailed": "Не удалось выполнить пакетное быстрое сопоставление!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Начато пакетное быстрое сопоставление {0} книг!",
|
||||||
"ToastBatchUpdateFailed": "Сбой пакетного обновления",
|
"ToastBatchUpdateFailed": "Сбой пакетного обновления",
|
||||||
"ToastBatchUpdateSuccess": "Успешное пакетное обновление",
|
"ToastBatchUpdateSuccess": "Успешное пакетное обновление",
|
||||||
"ToastBookmarkCreateFailed": "Не удалось создать закладку",
|
"ToastBookmarkCreateFailed": "Не удалось создать закладку",
|
||||||
@@ -849,6 +949,7 @@
|
|||||||
"ToastChaptersHaveErrors": "Главы имеют ошибки",
|
"ToastChaptersHaveErrors": "Главы имеют ошибки",
|
||||||
"ToastChaptersMustHaveTitles": "Главы должны содержать названия",
|
"ToastChaptersMustHaveTitles": "Главы должны содержать названия",
|
||||||
"ToastChaptersRemoved": "Удалены главы",
|
"ToastChaptersRemoved": "Удалены главы",
|
||||||
|
"ToastChaptersUpdated": "Обновленные главы",
|
||||||
"ToastCollectionItemsAddFailed": "Не удалось добавить элемент(ы) в коллекцию",
|
"ToastCollectionItemsAddFailed": "Не удалось добавить элемент(ы) в коллекцию",
|
||||||
"ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию",
|
"ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции",
|
"ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции",
|
||||||
@@ -866,10 +967,14 @@
|
|||||||
"ToastEncodeCancelSucces": "Кодирование отменено",
|
"ToastEncodeCancelSucces": "Кодирование отменено",
|
||||||
"ToastEpisodeDownloadQueueClearFailed": "Не удалось очистить очередь",
|
"ToastEpisodeDownloadQueueClearFailed": "Не удалось очистить очередь",
|
||||||
"ToastEpisodeDownloadQueueClearSuccess": "Очередь загрузки эпизода очищена",
|
"ToastEpisodeDownloadQueueClearSuccess": "Очередь загрузки эпизода очищена",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0 эпизодов обновлено",
|
||||||
"ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве",
|
"ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве",
|
||||||
"ToastFailedToLoadData": "Не удалось загрузить данные",
|
"ToastFailedToLoadData": "Не удалось загрузить данные",
|
||||||
|
"ToastFailedToMatch": "Не удалось найти совпадения",
|
||||||
"ToastFailedToShare": "Не удалось поделиться",
|
"ToastFailedToShare": "Не удалось поделиться",
|
||||||
|
"ToastFailedToUpdate": "Не удалось обновить",
|
||||||
"ToastInvalidImageUrl": "Неверный URL изображения",
|
"ToastInvalidImageUrl": "Неверный URL изображения",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Недопустимое максимальное количество загружаемых эпизодов",
|
||||||
"ToastInvalidUrl": "Неверный URL",
|
"ToastInvalidUrl": "Неверный URL",
|
||||||
"ToastItemCoverUpdateSuccess": "Обложка элемента обновлена",
|
"ToastItemCoverUpdateSuccess": "Обложка элемента обновлена",
|
||||||
"ToastItemDeletedFailed": "Не удалось удалить элемент",
|
"ToastItemDeletedFailed": "Не удалось удалить элемент",
|
||||||
@@ -887,14 +992,22 @@
|
|||||||
"ToastLibraryScanFailedToStart": "Не удалось запустить сканирование",
|
"ToastLibraryScanFailedToStart": "Не удалось запустить сканирование",
|
||||||
"ToastLibraryScanStarted": "Запущено сканирование библиотеки",
|
"ToastLibraryScanStarted": "Запущено сканирование библиотеки",
|
||||||
"ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена",
|
"ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена",
|
||||||
|
"ToastMatchAllAuthorsFailed": "Не удалось найти совпадения со всеми авторами",
|
||||||
|
"ToastMetadataFilesRemovedError": "Ошибка при удалении файлов metadata.{0}",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "В библиотеке не найдено файлов metadata.{0}",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Нет удаленных файлов metadata.{0}",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} файлов удалено",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Должен быть хотя бы один путь",
|
||||||
"ToastNameEmailRequired": "Имя и адрес электронной почты обязательны",
|
"ToastNameEmailRequired": "Имя и адрес электронной почты обязательны",
|
||||||
"ToastNameRequired": "Имя обязательно для заполнения",
|
"ToastNameRequired": "Имя обязательно для заполнения",
|
||||||
|
"ToastNewEpisodesFound": "{0} новых эпизодов найдено",
|
||||||
"ToastNewUserCreatedFailed": "Не удалось создать учетную запись: \"{0}\"",
|
"ToastNewUserCreatedFailed": "Не удалось создать учетную запись: \"{0}\"",
|
||||||
"ToastNewUserCreatedSuccess": "Новая учетная запись создана",
|
"ToastNewUserCreatedSuccess": "Новая учетная запись создана",
|
||||||
"ToastNewUserLibraryError": "Необходимо выбрать хотя бы одну библиотеку",
|
"ToastNewUserLibraryError": "Необходимо выбрать хотя бы одну библиотеку",
|
||||||
"ToastNewUserPasswordError": "Должен иметь пароль, только пользователь root может иметь пустой пароль",
|
"ToastNewUserPasswordError": "Должен иметь пароль, только пользователь root может иметь пустой пароль",
|
||||||
"ToastNewUserTagError": "Необходимо выбрать хотя бы один тег",
|
"ToastNewUserTagError": "Необходимо выбрать хотя бы один тег",
|
||||||
"ToastNewUserUsernameError": "Введите имя пользователя",
|
"ToastNewUserUsernameError": "Введите имя пользователя",
|
||||||
|
"ToastNoNewEpisodesFound": "Новых эпизодов не найдено",
|
||||||
"ToastNoUpdatesNecessary": "Обновления не требуются",
|
"ToastNoUpdatesNecessary": "Обновления не требуются",
|
||||||
"ToastNotificationCreateFailed": "Не удалось создать уведомление",
|
"ToastNotificationCreateFailed": "Не удалось создать уведомление",
|
||||||
"ToastNotificationDeleteFailed": "Не удалось удалить уведомление",
|
"ToastNotificationDeleteFailed": "Не удалось удалить уведомление",
|
||||||
@@ -913,6 +1026,7 @@
|
|||||||
"ToastPodcastGetFeedFailed": "Не удалось получить ленту подкастов",
|
"ToastPodcastGetFeedFailed": "Не удалось получить ленту подкастов",
|
||||||
"ToastPodcastNoEpisodesInFeed": "В RSS-ленте эпизодов не найдено",
|
"ToastPodcastNoEpisodesInFeed": "В RSS-ленте эпизодов не найдено",
|
||||||
"ToastPodcastNoRssFeed": "В подкасте нет RSS-канала",
|
"ToastPodcastNoRssFeed": "В подкасте нет RSS-канала",
|
||||||
|
"ToastProgressIsNotBeingSynced": "Прогресс не синхронизируется, перезапустите воспроизведение",
|
||||||
"ToastProviderCreatedFailed": "Не удалось добавить провайдера",
|
"ToastProviderCreatedFailed": "Не удалось добавить провайдера",
|
||||||
"ToastProviderCreatedSuccess": "Добавлен новый провайдер",
|
"ToastProviderCreatedSuccess": "Добавлен новый провайдер",
|
||||||
"ToastProviderNameAndUrlRequired": "Имя и URL обязательные",
|
"ToastProviderNameAndUrlRequired": "Имя и URL обязательные",
|
||||||
@@ -939,6 +1053,7 @@
|
|||||||
"ToastSessionCloseFailed": "Не удалось закрыть сеанс",
|
"ToastSessionCloseFailed": "Не удалось закрыть сеанс",
|
||||||
"ToastSessionDeleteFailed": "Не удалось удалить сеанс",
|
"ToastSessionDeleteFailed": "Не удалось удалить сеанс",
|
||||||
"ToastSessionDeleteSuccess": "Сеанс удален",
|
"ToastSessionDeleteSuccess": "Сеанс удален",
|
||||||
|
"ToastSleepTimerDone": "Выполнен таймер сна... Хр-р-р-р",
|
||||||
"ToastSlugMustChange": "Slug содержит недопустимые символы",
|
"ToastSlugMustChange": "Slug содержит недопустимые символы",
|
||||||
"ToastSlugRequired": "Требуется Slug",
|
"ToastSlugRequired": "Требуется Slug",
|
||||||
"ToastSocketConnected": "Сокет подключен",
|
"ToastSocketConnected": "Сокет подключен",
|
||||||
|
|||||||
+29
-19
@@ -136,7 +136,7 @@
|
|||||||
"HeaderEmailSettings": "Nastavitve e-pošte",
|
"HeaderEmailSettings": "Nastavitve e-pošte",
|
||||||
"HeaderEpisodes": "Epizode",
|
"HeaderEpisodes": "Epizode",
|
||||||
"HeaderEreaderDevices": "E-bralniki",
|
"HeaderEreaderDevices": "E-bralniki",
|
||||||
"HeaderEreaderSettings": "Nastavitve ebralnika",
|
"HeaderEreaderSettings": "Nastavitve e-bralnika",
|
||||||
"HeaderFiles": "Datoteke",
|
"HeaderFiles": "Datoteke",
|
||||||
"HeaderFindChapters": "Najdi poglavja",
|
"HeaderFindChapters": "Najdi poglavja",
|
||||||
"HeaderIgnoredFiles": "Prezrte datoteke",
|
"HeaderIgnoredFiles": "Prezrte datoteke",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "Posodobi obvestilo",
|
"HeaderNotificationUpdate": "Posodobi obvestilo",
|
||||||
"HeaderNotifications": "Obvestila",
|
"HeaderNotifications": "Obvestila",
|
||||||
"HeaderOpenIDConnectAuthentication": "Prijava z OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Prijava z OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Odprte seje poslušanja",
|
||||||
"HeaderOpenRSSFeed": "Odpri vir RSS",
|
"HeaderOpenRSSFeed": "Odpri vir RSS",
|
||||||
"HeaderOtherFiles": "Ostale datoteke",
|
"HeaderOtherFiles": "Ostale datoteke",
|
||||||
"HeaderPasswordAuthentication": "Preverjanje pristnosti z geslom",
|
"HeaderPasswordAuthentication": "Preverjanje pristnosti z geslom",
|
||||||
@@ -183,7 +184,7 @@
|
|||||||
"HeaderScheduleEpisodeDownloads": "Načrtovanje samodejnega prenosa epizod",
|
"HeaderScheduleEpisodeDownloads": "Načrtovanje samodejnega prenosa epizod",
|
||||||
"HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice",
|
"HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice",
|
||||||
"HeaderSession": "Seja",
|
"HeaderSession": "Seja",
|
||||||
"HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja",
|
"HeaderSetBackupSchedule": "Nastavi urnik varnostnega kopiranja",
|
||||||
"HeaderSettings": "Nastavitve",
|
"HeaderSettings": "Nastavitve",
|
||||||
"HeaderSettingsDisplay": "Zaslon",
|
"HeaderSettingsDisplay": "Zaslon",
|
||||||
"HeaderSettingsExperimental": "Eksperimentalne funkcije",
|
"HeaderSettingsExperimental": "Eksperimentalne funkcije",
|
||||||
@@ -226,6 +227,7 @@
|
|||||||
"LabelAllUsersExcludingGuests": "Vsi uporabniki razen gosti",
|
"LabelAllUsersExcludingGuests": "Vsi uporabniki razen gosti",
|
||||||
"LabelAllUsersIncludingGuests": "Vsi uporabniki vključno z gosti",
|
"LabelAllUsersIncludingGuests": "Vsi uporabniki vključno z gosti",
|
||||||
"LabelAlreadyInYourLibrary": "Že v tvoji knjižnici",
|
"LabelAlreadyInYourLibrary": "Že v tvoji knjižnici",
|
||||||
|
"LabelApiToken": "API žeton",
|
||||||
"LabelAppend": "Priloži",
|
"LabelAppend": "Priloži",
|
||||||
"LabelAudioBitrate": "Avdio bitna hitrost (npr. 128k)",
|
"LabelAudioBitrate": "Avdio bitna hitrost (npr. 128k)",
|
||||||
"LabelAudioChannels": "Avdio kanali (1 ali 2)",
|
"LabelAudioChannels": "Avdio kanali (1 ali 2)",
|
||||||
@@ -243,7 +245,7 @@
|
|||||||
"LabelAutoRegisterDescription": "Po prijavi samodejno ustvari nove uporabnike",
|
"LabelAutoRegisterDescription": "Po prijavi samodejno ustvari nove uporabnike",
|
||||||
"LabelBackToUser": "Nazaj na uporabnika",
|
"LabelBackToUser": "Nazaj na uporabnika",
|
||||||
"LabelBackupAudioFiles": "Varnostno kopiranje zvočnih datotek",
|
"LabelBackupAudioFiles": "Varnostno kopiranje zvočnih datotek",
|
||||||
"LabelBackupLocation": "Lokacija rezervne kopije",
|
"LabelBackupLocation": "Lokacija varnostnih kopij",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Omogoči samodejno varnostno kopiranje",
|
"LabelBackupsEnableAutomaticBackups": "Omogoči samodejno varnostno kopiranje",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Varnostne kopije shranjene v /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Varnostne kopije shranjene v /metadata/backups",
|
||||||
"LabelBackupsMaxBackupSize": "Največja velikost varnostne kopije (v GB) (0 za neomejeno)",
|
"LabelBackupsMaxBackupSize": "Največja velikost varnostne kopije (v GB) (0 za neomejeno)",
|
||||||
@@ -325,7 +327,7 @@
|
|||||||
"LabelEndOfChapter": "Konec poglavja",
|
"LabelEndOfChapter": "Konec poglavja",
|
||||||
"LabelEpisode": "Epizoda",
|
"LabelEpisode": "Epizoda",
|
||||||
"LabelEpisodeNotLinkedToRssFeed": "Epizoda ni povezana z virom RSS",
|
"LabelEpisodeNotLinkedToRssFeed": "Epizoda ni povezana z virom RSS",
|
||||||
"LabelEpisodeNumber": "Epizoda #{0}",
|
"LabelEpisodeNumber": "{0}. epizoda",
|
||||||
"LabelEpisodeTitle": "Naslov epizode",
|
"LabelEpisodeTitle": "Naslov epizode",
|
||||||
"LabelEpisodeType": "Tip epizode",
|
"LabelEpisodeType": "Tip epizode",
|
||||||
"LabelEpisodeUrlFromRssFeed": "URL epizode iz vira RSS",
|
"LabelEpisodeUrlFromRssFeed": "URL epizode iz vira RSS",
|
||||||
@@ -364,7 +366,7 @@
|
|||||||
"LabelHardDeleteFile": "Trdo brisanje datoteke",
|
"LabelHardDeleteFile": "Trdo brisanje datoteke",
|
||||||
"LabelHasEbook": "Ima e-knjigo",
|
"LabelHasEbook": "Ima e-knjigo",
|
||||||
"LabelHasSupplementaryEbook": "Ima dodatno e-knjigo",
|
"LabelHasSupplementaryEbook": "Ima dodatno e-knjigo",
|
||||||
"LabelHideSubtitles": "Skrij podnapise",
|
"LabelHideSubtitles": "Skrij podnaslove",
|
||||||
"LabelHighestPriority": "Najvišja prioriteta",
|
"LabelHighestPriority": "Najvišja prioriteta",
|
||||||
"LabelHost": "Gostitelj",
|
"LabelHost": "Gostitelj",
|
||||||
"LabelHour": "Ura",
|
"LabelHour": "Ura",
|
||||||
@@ -393,7 +395,7 @@
|
|||||||
"LabelLastBookAdded": "Zadnja dodana knjiga",
|
"LabelLastBookAdded": "Zadnja dodana knjiga",
|
||||||
"LabelLastBookUpdated": "Zadnja posodobljena knjiga",
|
"LabelLastBookUpdated": "Zadnja posodobljena knjiga",
|
||||||
"LabelLastSeen": "Nazadnje viden",
|
"LabelLastSeen": "Nazadnje viden",
|
||||||
"LabelLastTime": "Zadnji čas",
|
"LabelLastTime": "Nazadnje",
|
||||||
"LabelLastUpdate": "Zadnja posodobitev",
|
"LabelLastUpdate": "Zadnja posodobitev",
|
||||||
"LabelLayout": "Postavitev",
|
"LabelLayout": "Postavitev",
|
||||||
"LabelLayoutSinglePage": "Ena stran",
|
"LabelLayoutSinglePage": "Ena stran",
|
||||||
@@ -405,7 +407,7 @@
|
|||||||
"LabelLibraryItem": "Element knjižnice",
|
"LabelLibraryItem": "Element knjižnice",
|
||||||
"LabelLibraryName": "Ime knjižnice",
|
"LabelLibraryName": "Ime knjižnice",
|
||||||
"LabelLimit": "Omejitev",
|
"LabelLimit": "Omejitev",
|
||||||
"LabelLineSpacing": "Razmik med vrsticami",
|
"LabelLineSpacing": "Vrstični razmak",
|
||||||
"LabelListenAgain": "Poslušaj znova",
|
"LabelListenAgain": "Poslušaj znova",
|
||||||
"LabelLogLevelDebug": "Odpravljanje napak",
|
"LabelLogLevelDebug": "Odpravljanje napak",
|
||||||
"LabelLogLevelInfo": "Info",
|
"LabelLogLevelInfo": "Info",
|
||||||
@@ -457,18 +459,20 @@
|
|||||||
"LabelNotificationsMaxQueueSize": "Največja velikost čakalne vrste za dogodke obvestil",
|
"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.",
|
"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",
|
"LabelNumberOfBooks": "Število knjig",
|
||||||
"LabelNumberOfEpisodes": "# od epizod",
|
"LabelNumberOfEpisodes": "število 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:",
|
"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'.",
|
"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.",
|
"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",
|
"LabelOpenRSSFeed": "Odpri vir RSS",
|
||||||
"LabelOverwrite": "Prepiši",
|
"LabelOverwrite": "Prepiši",
|
||||||
|
"LabelPaginationPageXOfY": "Stran {0} od {1}",
|
||||||
"LabelPassword": "Geslo",
|
"LabelPassword": "Geslo",
|
||||||
"LabelPath": "Pot",
|
"LabelPath": "Pot",
|
||||||
"LabelPermanent": "Trajno",
|
"LabelPermanent": "Trajno",
|
||||||
"LabelPermissionsAccessAllLibraries": "Lahko dostopa do vseh knjižnic",
|
"LabelPermissionsAccessAllLibraries": "Lahko dostopa do vseh knjižnic",
|
||||||
"LabelPermissionsAccessAllTags": "Lahko dostopa do vseh oznak",
|
"LabelPermissionsAccessAllTags": "Lahko dostopa do vseh oznak",
|
||||||
"LabelPermissionsAccessExplicitContent": "Lahko dostopa do eksplicitne vsebine",
|
"LabelPermissionsAccessExplicitContent": "Lahko dostopa do eksplicitne vsebine",
|
||||||
|
"LabelPermissionsCreateEreader": "Lahko ustvari e-bralnik",
|
||||||
"LabelPermissionsDelete": "Lahko briše",
|
"LabelPermissionsDelete": "Lahko briše",
|
||||||
"LabelPermissionsDownload": "Lahko prenaša",
|
"LabelPermissionsDownload": "Lahko prenaša",
|
||||||
"LabelPermissionsUpdate": "Lahko posodablja",
|
"LabelPermissionsUpdate": "Lahko posodablja",
|
||||||
@@ -491,7 +495,7 @@
|
|||||||
"LabelProviderAuthorizationValue": "Vrednost glave avtorizacije",
|
"LabelProviderAuthorizationValue": "Vrednost glave avtorizacije",
|
||||||
"LabelPubDate": "Datum objave",
|
"LabelPubDate": "Datum objave",
|
||||||
"LabelPublishYear": "Leto izdaje",
|
"LabelPublishYear": "Leto izdaje",
|
||||||
"LabelPublishedDate": "Izdano {0}",
|
"LabelPublishedDate": "Objavljeno {0}",
|
||||||
"LabelPublishedDecade": "Desetletje izdaje",
|
"LabelPublishedDecade": "Desetletje izdaje",
|
||||||
"LabelPublishedDecades": "Desetletja izdaje",
|
"LabelPublishedDecades": "Desetletja izdaje",
|
||||||
"LabelPublisher": "Izdajatelj",
|
"LabelPublisher": "Izdajatelj",
|
||||||
@@ -559,10 +563,13 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Serije, ki imajo eno knjigo, bodo skrite na strani serije in policah domače strani.",
|
"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",
|
"LabelSettingsHomePageBookshelfView": "Domača stran bo imela pogled knjižne police",
|
||||||
"LabelSettingsLibraryBookshelfView": "Knjižnična uporaba pogleda knjižne police",
|
"LabelSettingsLibraryBookshelfView": "Knjižnična uporaba pogleda knjižne police",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Odstotek dokončanega je večji od",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Preostali čas je manj kot (sekund)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Označi medijski element kot končan, ko",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči prejšnje knjige v nadaljevanju serije",
|
"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.",
|
"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",
|
"LabelSettingsParseSubtitles": "Razčleni podnaslove",
|
||||||
"LabelSettingsParseSubtitlesHelp": "Izvleci podnapise iz imen map zvočnih knjig.<br>Podnapis mora biti ločen z \" - \"<br>npr. \"Naslov knjige – tu podnapis\" ima podnapis \"tu podnapis\"",
|
"LabelSettingsParseSubtitlesHelp": "Izvleci padnaslove iz imen map zvočnih knjig.<br>Podnaslov mora biti ločen z \" - \"<br>npr. \"Naslov knjige – tu podnaslove\" ima podnaslov \"tu podnaslov\"",
|
||||||
"LabelSettingsPreferMatchedMetadata": "Prednost imajo ujemajoči se metapodatki",
|
"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.",
|
"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",
|
"LabelSettingsSkipMatchingBooksWithASIN": "Preskoči ujemajoče se knjige, ki že imajo ASIN",
|
||||||
@@ -581,12 +588,12 @@
|
|||||||
"LabelShareURL": "Deli URL",
|
"LabelShareURL": "Deli URL",
|
||||||
"LabelShowAll": "Prikaži vse",
|
"LabelShowAll": "Prikaži vse",
|
||||||
"LabelShowSeconds": "Prikaži sekunde",
|
"LabelShowSeconds": "Prikaži sekunde",
|
||||||
"LabelShowSubtitles": "Prikaži podnapise",
|
"LabelShowSubtitles": "Prikaži podnaslove",
|
||||||
"LabelSize": "Velikost",
|
"LabelSize": "Velikost",
|
||||||
"LabelSleepTimer": "Časovnik za spanje",
|
"LabelSleepTimer": "Časovnik za spanje",
|
||||||
"LabelSlug": "Slug",
|
"LabelSlug": "Slug",
|
||||||
"LabelStart": "Začetek",
|
"LabelStart": "Začetek",
|
||||||
"LabelStartTime": "Začetni čas",
|
"LabelStartTime": "Čas začetka",
|
||||||
"LabelStarted": "Začeto",
|
"LabelStarted": "Začeto",
|
||||||
"LabelStartedAt": "Začeto ob",
|
"LabelStartedAt": "Začeto ob",
|
||||||
"LabelStatsAudioTracks": "Zvočni posnetki",
|
"LabelStatsAudioTracks": "Zvočni posnetki",
|
||||||
@@ -604,7 +611,7 @@
|
|||||||
"LabelStatsOverallDays": "Skupaj dnevi",
|
"LabelStatsOverallDays": "Skupaj dnevi",
|
||||||
"LabelStatsOverallHours": "Skupaj ur",
|
"LabelStatsOverallHours": "Skupaj ur",
|
||||||
"LabelStatsWeekListening": "Tednov poslušanja",
|
"LabelStatsWeekListening": "Tednov poslušanja",
|
||||||
"LabelSubtitle": "Podnapis",
|
"LabelSubtitle": "Podnaslov",
|
||||||
"LabelSupportedFileTypes": "Podprte vrste datotek",
|
"LabelSupportedFileTypes": "Podprte vrste datotek",
|
||||||
"LabelTag": "Oznaka",
|
"LabelTag": "Oznaka",
|
||||||
"LabelTags": "Oznake",
|
"LabelTags": "Oznake",
|
||||||
@@ -618,7 +625,7 @@
|
|||||||
"LabelTheme": "Tema",
|
"LabelTheme": "Tema",
|
||||||
"LabelThemeDark": "Temna",
|
"LabelThemeDark": "Temna",
|
||||||
"LabelThemeLight": "Svetla",
|
"LabelThemeLight": "Svetla",
|
||||||
"LabelTimeBase": "Odvisna od časa",
|
"LabelTimeBase": "Osnovni čas",
|
||||||
"LabelTimeDurationXHours": "{0} ur",
|
"LabelTimeDurationXHours": "{0} ur",
|
||||||
"LabelTimeDurationXMinutes": "{0} minut",
|
"LabelTimeDurationXMinutes": "{0} minut",
|
||||||
"LabelTimeDurationXSeconds": "{0} sekund",
|
"LabelTimeDurationXSeconds": "{0} sekund",
|
||||||
@@ -656,6 +663,7 @@
|
|||||||
"LabelUpdateDetailsHelp": "Dovoli prepisovanje obstoječih podrobnosti za izbrane knjige, ko se najde ujemanje",
|
"LabelUpdateDetailsHelp": "Dovoli prepisovanje obstoječih podrobnosti za izbrane knjige, ko se najde ujemanje",
|
||||||
"LabelUpdatedAt": "Posodobljeno ob",
|
"LabelUpdatedAt": "Posodobljeno ob",
|
||||||
"LabelUploaderDragAndDrop": "Povleci in spusti datoteke ali mape",
|
"LabelUploaderDragAndDrop": "Povleci in spusti datoteke ali mape",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Povleci in spusti datoteke",
|
||||||
"LabelUploaderDropFiles": "Spusti datoteke",
|
"LabelUploaderDropFiles": "Spusti datoteke",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Samodejno pridobi naslov, avtorja in serijo",
|
"LabelUploaderItemFetchMetadataHelp": "Samodejno pridobi naslov, avtorja in serijo",
|
||||||
"LabelUseAdvancedOptions": "Uporabi napredne možnosti",
|
"LabelUseAdvancedOptions": "Uporabi napredne možnosti",
|
||||||
@@ -671,11 +679,13 @@
|
|||||||
"LabelViewPlayerSettings": "Ogled nastavitev predvajalnika",
|
"LabelViewPlayerSettings": "Ogled nastavitev predvajalnika",
|
||||||
"LabelViewQueue": "Ogled čakalno vrsto predvajalnika",
|
"LabelViewQueue": "Ogled čakalno vrsto predvajalnika",
|
||||||
"LabelVolume": "Glasnost",
|
"LabelVolume": "Glasnost",
|
||||||
|
"LabelWebRedirectURLsDescription": "Avtorizirajte URL-je pri svojem ponudniku OAuth ter s tem omogočite preusmeritev nazaj v spletno aplikacijo po prijavi:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Podmapa za URL-je preusmeritve",
|
||||||
"LabelWeekdaysToRun": "Delovni dnevi predvajanja",
|
"LabelWeekdaysToRun": "Delovni dnevi predvajanja",
|
||||||
"LabelXBooks": "{0} knjig",
|
"LabelXBooks": "{0} knjig",
|
||||||
"LabelXItems": "{0} elementov",
|
"LabelXItems": "{0} elementov",
|
||||||
"LabelYearReviewHide": "Skrij pregled leta",
|
"LabelYearReviewHide": "Skrij pregled leta",
|
||||||
"LabelYearReviewShow": "Poglej pregled leta",
|
"LabelYearReviewShow": "Poglej si pregled leta",
|
||||||
"LabelYourAudiobookDuration": "Trajanje tvojih zvočnih knjig",
|
"LabelYourAudiobookDuration": "Trajanje tvojih zvočnih knjig",
|
||||||
"LabelYourBookmarks": "Tvoji zaznamki",
|
"LabelYourBookmarks": "Tvoji zaznamki",
|
||||||
"LabelYourPlaylists": "Tvoje seznami predvajanj",
|
"LabelYourPlaylists": "Tvoje seznami predvajanj",
|
||||||
@@ -766,7 +776,7 @@
|
|||||||
"MessageMarkAllEpisodesNotFinished": "Označi vse epizode kot nedokončane",
|
"MessageMarkAllEpisodesNotFinished": "Označi vse epizode kot nedokončane",
|
||||||
"MessageMarkAsFinished": "Označi kot dokončano",
|
"MessageMarkAsFinished": "Označi kot dokončano",
|
||||||
"MessageMarkAsNotFinished": "Označi kot nedokonč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 prepisuje čez obstoječe podatke.",
|
"MessageMatchBooksDescription": "bo poskušalo povezati knjige v knjižnici s knjigo izbranega ponudnika iskanja in izpolniti prazne podatke in naslovnico. Ne prepisuje čez obstoječe podatke.",
|
||||||
"MessageNoAudioTracks": "Ni zvočnih posnetkov",
|
"MessageNoAudioTracks": "Ni zvočnih posnetkov",
|
||||||
"MessageNoAuthors": "Brez avtorjev",
|
"MessageNoAuthors": "Brez avtorjev",
|
||||||
"MessageNoBackups": "Brez varnostnih kopij",
|
"MessageNoBackups": "Brez varnostnih kopij",
|
||||||
@@ -822,7 +832,7 @@
|
|||||||
"MessageSearchResultsFor": "Rezultati iskanja za",
|
"MessageSearchResultsFor": "Rezultati iskanja za",
|
||||||
"MessageSelected": "{0} izbrano",
|
"MessageSelected": "{0} izbrano",
|
||||||
"MessageServerCouldNotBeReached": "Strežnika ni bilo mogoče doseči",
|
"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",
|
"MessageSetChaptersFromTracksDescription": "Nastavi poglavja z uporabo vsake zvočne datoteke kot poglavja in naslova poglavja kot imena zvočne datoteke",
|
||||||
"MessageShareExpirationWillBe": "Potečeno bo <strong>{0}</strong>",
|
"MessageShareExpirationWillBe": "Potečeno bo <strong>{0}</strong>",
|
||||||
"MessageShareExpiresIn": "Poteče čez {0}",
|
"MessageShareExpiresIn": "Poteče čez {0}",
|
||||||
"MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>",
|
"MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>",
|
||||||
@@ -895,7 +905,7 @@
|
|||||||
"StatsBooksFinishedThisYear": "Nekaj knjig, ki so bile dokončane letos…",
|
"StatsBooksFinishedThisYear": "Nekaj knjig, ki so bile dokončane letos…",
|
||||||
"StatsBooksListenedTo": "poslušanih knjig",
|
"StatsBooksListenedTo": "poslušanih knjig",
|
||||||
"StatsCollectionGrewTo": "Vaša zbirka knjig se je povečala na …",
|
"StatsCollectionGrewTo": "Vaša zbirka knjig se je povečala na …",
|
||||||
"StatsSessions": "sej",
|
"StatsSessions": "seje",
|
||||||
"StatsSpentListening": "porabil za poslušanje",
|
"StatsSpentListening": "porabil za poslušanje",
|
||||||
"StatsTopAuthor": "TOP AVTOR",
|
"StatsTopAuthor": "TOP AVTOR",
|
||||||
"StatsTopAuthors": "TOP AVTORJI",
|
"StatsTopAuthors": "TOP AVTORJI",
|
||||||
|
|||||||
+223
-1
@@ -19,6 +19,7 @@
|
|||||||
"ButtonChooseFiles": "Обрати файли",
|
"ButtonChooseFiles": "Обрати файли",
|
||||||
"ButtonClearFilter": "Очистити фільтр",
|
"ButtonClearFilter": "Очистити фільтр",
|
||||||
"ButtonCloseFeed": "Закрити стрічку",
|
"ButtonCloseFeed": "Закрити стрічку",
|
||||||
|
"ButtonCloseSession": "Закрити відкритий сеанс",
|
||||||
"ButtonCollections": "Добірки",
|
"ButtonCollections": "Добірки",
|
||||||
"ButtonConfigureScanner": "Налаштувати сканер",
|
"ButtonConfigureScanner": "Налаштувати сканер",
|
||||||
"ButtonCreate": "Створити",
|
"ButtonCreate": "Створити",
|
||||||
@@ -28,6 +29,9 @@
|
|||||||
"ButtonEdit": "Редагувати",
|
"ButtonEdit": "Редагувати",
|
||||||
"ButtonEditChapters": "Редагувати глави",
|
"ButtonEditChapters": "Редагувати глави",
|
||||||
"ButtonEditPodcast": "Редагувати подкаст",
|
"ButtonEditPodcast": "Редагувати подкаст",
|
||||||
|
"ButtonEnable": "Увімкнути",
|
||||||
|
"ButtonFireAndFail": "Вогонь і невдача",
|
||||||
|
"ButtonFireOnTest": "Випробування на вогнестійкість",
|
||||||
"ButtonForceReScan": "Примусово сканувати",
|
"ButtonForceReScan": "Примусово сканувати",
|
||||||
"ButtonFullPath": "Повний шлях",
|
"ButtonFullPath": "Повний шлях",
|
||||||
"ButtonHide": "Приховати",
|
"ButtonHide": "Приховати",
|
||||||
@@ -46,19 +50,23 @@
|
|||||||
"ButtonNevermind": "Скасувати",
|
"ButtonNevermind": "Скасувати",
|
||||||
"ButtonNext": "Наступний",
|
"ButtonNext": "Наступний",
|
||||||
"ButtonNextChapter": "Наступна глава",
|
"ButtonNextChapter": "Наступна глава",
|
||||||
|
"ButtonNextItemInQueue": "Наступний елемент у черзі",
|
||||||
"ButtonOk": "Гаразд",
|
"ButtonOk": "Гаразд",
|
||||||
"ButtonOpenFeed": "Відкрити стрічку",
|
"ButtonOpenFeed": "Відкрити стрічку",
|
||||||
"ButtonOpenManager": "Відкрити менеджер",
|
"ButtonOpenManager": "Відкрити менеджер",
|
||||||
"ButtonPause": "Пауза",
|
"ButtonPause": "Пауза",
|
||||||
"ButtonPlay": "Слухати",
|
"ButtonPlay": "Слухати",
|
||||||
|
"ButtonPlayAll": "Відтворити все",
|
||||||
"ButtonPlaying": "Відтворюється",
|
"ButtonPlaying": "Відтворюється",
|
||||||
"ButtonPlaylists": "Списки відтворення",
|
"ButtonPlaylists": "Списки відтворення",
|
||||||
"ButtonPrevious": "Попередній",
|
"ButtonPrevious": "Попередній",
|
||||||
"ButtonPreviousChapter": "Попередня глава",
|
"ButtonPreviousChapter": "Попередня глава",
|
||||||
|
"ButtonProbeAudioFile": "Перевірити аудіофайл",
|
||||||
"ButtonPurgeAllCache": "Очистити весь кеш",
|
"ButtonPurgeAllCache": "Очистити весь кеш",
|
||||||
"ButtonPurgeItemsCache": "Очистити кеш елементів",
|
"ButtonPurgeItemsCache": "Очистити кеш елементів",
|
||||||
"ButtonQueueAddItem": "Додати до черги",
|
"ButtonQueueAddItem": "Додати до черги",
|
||||||
"ButtonQueueRemoveItem": "Вилучити з черги",
|
"ButtonQueueRemoveItem": "Вилучити з черги",
|
||||||
|
"ButtonQuickEmbed": "Швидке вбудовування",
|
||||||
"ButtonQuickEmbedMetadata": "Швидко вбудувати метадані",
|
"ButtonQuickEmbedMetadata": "Швидко вбудувати метадані",
|
||||||
"ButtonQuickMatch": "Швидкий пошук",
|
"ButtonQuickMatch": "Швидкий пошук",
|
||||||
"ButtonReScan": "Пересканувати",
|
"ButtonReScan": "Пересканувати",
|
||||||
@@ -92,6 +100,7 @@
|
|||||||
"ButtonStats": "Статистика",
|
"ButtonStats": "Статистика",
|
||||||
"ButtonSubmit": "Надіслати",
|
"ButtonSubmit": "Надіслати",
|
||||||
"ButtonTest": "Перевірити",
|
"ButtonTest": "Перевірити",
|
||||||
|
"ButtonUnlinkOpenId": "Вимкнути OpenID",
|
||||||
"ButtonUpload": "Завантажити",
|
"ButtonUpload": "Завантажити",
|
||||||
"ButtonUploadBackup": "Завантажити резервну копію",
|
"ButtonUploadBackup": "Завантажити резервну копію",
|
||||||
"ButtonUploadCover": "Завантажити обкладинку",
|
"ButtonUploadCover": "Завантажити обкладинку",
|
||||||
@@ -104,6 +113,7 @@
|
|||||||
"ErrorUploadFetchMetadataNoResults": "Не вдалося отримати метадані — спробуйте оновити заголовок та/або автора",
|
"ErrorUploadFetchMetadataNoResults": "Не вдалося отримати метадані — спробуйте оновити заголовок та/або автора",
|
||||||
"ErrorUploadLacksTitle": "Назва обов'язкова",
|
"ErrorUploadLacksTitle": "Назва обов'язкова",
|
||||||
"HeaderAccount": "Профіль",
|
"HeaderAccount": "Профіль",
|
||||||
|
"HeaderAddCustomMetadataProvider": "Додати користувацький постачальник метаданих",
|
||||||
"HeaderAdvanced": "Розширені",
|
"HeaderAdvanced": "Розширені",
|
||||||
"HeaderAppriseNotificationSettings": "Налаштування сповіщень Apprise",
|
"HeaderAppriseNotificationSettings": "Налаштування сповіщень Apprise",
|
||||||
"HeaderAudioTracks": "Аудіодоріжки",
|
"HeaderAudioTracks": "Аудіодоріжки",
|
||||||
@@ -149,8 +159,11 @@
|
|||||||
"HeaderMetadataToEmbed": "Вбудувати метадані",
|
"HeaderMetadataToEmbed": "Вбудувати метадані",
|
||||||
"HeaderNewAccount": "Новий профіль",
|
"HeaderNewAccount": "Новий профіль",
|
||||||
"HeaderNewLibrary": "Нова бібліотека",
|
"HeaderNewLibrary": "Нова бібліотека",
|
||||||
|
"HeaderNotificationCreate": "Створити сповіщення",
|
||||||
|
"HeaderNotificationUpdate": "Оновити сповіщення",
|
||||||
"HeaderNotifications": "Сповіщення",
|
"HeaderNotifications": "Сповіщення",
|
||||||
"HeaderOpenIDConnectAuthentication": "Автентифікація OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Автентифікація OpenID Connect",
|
||||||
|
"HeaderOpenListeningSessions": "Відкриті сеанси прослуховування",
|
||||||
"HeaderOpenRSSFeed": "Відкрити RSS-канал",
|
"HeaderOpenRSSFeed": "Відкрити RSS-канал",
|
||||||
"HeaderOtherFiles": "Інші файли",
|
"HeaderOtherFiles": "Інші файли",
|
||||||
"HeaderPasswordAuthentication": "Автентифікація за паролем",
|
"HeaderPasswordAuthentication": "Автентифікація за паролем",
|
||||||
@@ -168,6 +181,7 @@
|
|||||||
"HeaderRemoveEpisodes": "Видалити епізодів: {0}",
|
"HeaderRemoveEpisodes": "Видалити епізодів: {0}",
|
||||||
"HeaderSavedMediaProgress": "Збережений прогрес медіа",
|
"HeaderSavedMediaProgress": "Збережений прогрес медіа",
|
||||||
"HeaderSchedule": "Розклад",
|
"HeaderSchedule": "Розклад",
|
||||||
|
"HeaderScheduleEpisodeDownloads": "Запланувати автоматичне завантаження епізодів",
|
||||||
"HeaderScheduleLibraryScans": "Розклад автосканування бібліотеки",
|
"HeaderScheduleLibraryScans": "Розклад автосканування бібліотеки",
|
||||||
"HeaderSession": "Сеанс",
|
"HeaderSession": "Сеанс",
|
||||||
"HeaderSetBackupSchedule": "Встановити розклад резервного копіювання",
|
"HeaderSetBackupSchedule": "Встановити розклад резервного копіювання",
|
||||||
@@ -206,13 +220,18 @@
|
|||||||
"LabelAddToPlaylist": "Додати до списку відтворення",
|
"LabelAddToPlaylist": "Додати до списку відтворення",
|
||||||
"LabelAddToPlaylistBatch": "Додано елементів у список відтворення: {0}",
|
"LabelAddToPlaylistBatch": "Додано елементів у список відтворення: {0}",
|
||||||
"LabelAddedAt": "Дата додавання",
|
"LabelAddedAt": "Дата додавання",
|
||||||
|
"LabelAddedDate": "Додано {0}",
|
||||||
"LabelAdminUsersOnly": "Тільки для адміністраторів",
|
"LabelAdminUsersOnly": "Тільки для адміністраторів",
|
||||||
"LabelAll": "Усе",
|
"LabelAll": "Усе",
|
||||||
"LabelAllUsers": "Усі користувачі",
|
"LabelAllUsers": "Усі користувачі",
|
||||||
"LabelAllUsersExcludingGuests": "Усі, крім гостей",
|
"LabelAllUsersExcludingGuests": "Усі, крім гостей",
|
||||||
"LabelAllUsersIncludingGuests": "Усі, включно з гостями",
|
"LabelAllUsersIncludingGuests": "Усі, включно з гостями",
|
||||||
"LabelAlreadyInYourLibrary": "Вже у вашій бібліотеці",
|
"LabelAlreadyInYourLibrary": "Вже у вашій бібліотеці",
|
||||||
|
"LabelApiToken": "Токен API",
|
||||||
"LabelAppend": "Додати",
|
"LabelAppend": "Додати",
|
||||||
|
"LabelAudioBitrate": "Бітрейт аудіо (напр. 128k)",
|
||||||
|
"LabelAudioChannels": "Канали аудіо (1 або 2)",
|
||||||
|
"LabelAudioCodec": "Аудіокодек",
|
||||||
"LabelAuthor": "Автор",
|
"LabelAuthor": "Автор",
|
||||||
"LabelAuthorFirstLast": "Автор (за ім'ям)",
|
"LabelAuthorFirstLast": "Автор (за ім'ям)",
|
||||||
"LabelAuthorLastFirst": "Автор (за прізвищем)",
|
"LabelAuthorLastFirst": "Автор (за прізвищем)",
|
||||||
@@ -225,6 +244,7 @@
|
|||||||
"LabelAutoRegister": "Автореєстрація",
|
"LabelAutoRegister": "Автореєстрація",
|
||||||
"LabelAutoRegisterDescription": "Автоматично створювати нових користувачів після входу",
|
"LabelAutoRegisterDescription": "Автоматично створювати нових користувачів після входу",
|
||||||
"LabelBackToUser": "Повернутися до користувача",
|
"LabelBackToUser": "Повернутися до користувача",
|
||||||
|
"LabelBackupAudioFiles": "Резервне копіювання аудіофайлів",
|
||||||
"LabelBackupLocation": "Розташування резервних копій",
|
"LabelBackupLocation": "Розташування резервних копій",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Автоматичне резервне копіювання",
|
"LabelBackupsEnableAutomaticBackups": "Автоматичне резервне копіювання",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Резервні копії збережено у /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Резервні копії збережено у /metadata/backups",
|
||||||
@@ -233,18 +253,22 @@
|
|||||||
"LabelBackupsNumberToKeep": "Кількість резервних копій",
|
"LabelBackupsNumberToKeep": "Кількість резервних копій",
|
||||||
"LabelBackupsNumberToKeepHelp": "Лиш 1 резервну копію буде видалено за раз, тож якщо їх багато, то вам варто видалити їх вручну.",
|
"LabelBackupsNumberToKeepHelp": "Лиш 1 резервну копію буде видалено за раз, тож якщо їх багато, то вам варто видалити їх вручну.",
|
||||||
"LabelBitrate": "Бітрейт",
|
"LabelBitrate": "Бітрейт",
|
||||||
|
"LabelBonus": "Бонус",
|
||||||
"LabelBooks": "Книги",
|
"LabelBooks": "Книги",
|
||||||
"LabelButtonText": "Текст кнопки",
|
"LabelButtonText": "Текст кнопки",
|
||||||
"LabelByAuthor": "від {0}",
|
"LabelByAuthor": "від {0}",
|
||||||
"LabelChangePassword": "Змінити пароль",
|
"LabelChangePassword": "Змінити пароль",
|
||||||
"LabelChannels": "Канали",
|
"LabelChannels": "Канали",
|
||||||
|
"LabelChapterCount": "{0} Глав",
|
||||||
"LabelChapterTitle": "Назва глави",
|
"LabelChapterTitle": "Назва глави",
|
||||||
"LabelChapters": "Глави",
|
"LabelChapters": "Глави",
|
||||||
"LabelChaptersFound": "глав знайдено",
|
"LabelChaptersFound": "глав знайдено",
|
||||||
"LabelClickForMoreInfo": "Натисніть, щоб дізнатися більше",
|
"LabelClickForMoreInfo": "Натисніть, щоб дізнатися більше",
|
||||||
|
"LabelClickToUseCurrentValue": "Натисніть, щоб використати поточне значення",
|
||||||
"LabelClosePlayer": "Закрити програвач",
|
"LabelClosePlayer": "Закрити програвач",
|
||||||
"LabelCodec": "Кодек",
|
"LabelCodec": "Кодек",
|
||||||
"LabelCollapseSeries": "Згорнути серії",
|
"LabelCollapseSeries": "Згорнути серії",
|
||||||
|
"LabelCollapseSubSeries": "Згорнути підсерії",
|
||||||
"LabelCollection": "Добірка",
|
"LabelCollection": "Добірка",
|
||||||
"LabelCollections": "Добірки",
|
"LabelCollections": "Добірки",
|
||||||
"LabelComplete": "Завершити",
|
"LabelComplete": "Завершити",
|
||||||
@@ -290,13 +314,28 @@
|
|||||||
"LabelEmailSettingsTestAddress": "Тестова адреса",
|
"LabelEmailSettingsTestAddress": "Тестова адреса",
|
||||||
"LabelEmbeddedCover": "Вбудована обкладинка",
|
"LabelEmbeddedCover": "Вбудована обкладинка",
|
||||||
"LabelEnable": "Увімкнути",
|
"LabelEnable": "Увімкнути",
|
||||||
|
"LabelEncodingBackupLocation": "Резервна копія ваших оригінальних аудіофайлів буде збережена в:",
|
||||||
|
"LabelEncodingChaptersNotEmbedded": "Глави не вбудовуються в багатодоріжкові аудіокниги.",
|
||||||
|
"LabelEncodingClearItemCache": "Переконайтесь, що періодично очищуєте кеш елементів.",
|
||||||
|
"LabelEncodingFinishedM4B": "Готовий M4B буде поміщений у вашу папку з аудіокнигами за адресою:",
|
||||||
|
"LabelEncodingInfoEmbedded": "Метадані будуть вбудовані в звукові доріжки всередині папки вашої аудіокниги.",
|
||||||
|
"LabelEncodingStartedNavigation": "Як тільки завдання розпочнеться, ви можете покинути цю сторінку.",
|
||||||
|
"LabelEncodingTimeWarning": "Кодування може зайняти до 30 хвилин.",
|
||||||
|
"LabelEncodingWarningAdvancedSettings": "Увага: не змінюйте ці налаштування, якщо ви не знайомі з параметрами кодування ffmpeg.",
|
||||||
|
"LabelEncodingWatcherDisabled": "Якщо у вас вимкнено спостереження за папкою, вам потрібно буде повторно відсканувати цю аудіокнигу.",
|
||||||
"LabelEnd": "Кінець",
|
"LabelEnd": "Кінець",
|
||||||
"LabelEndOfChapter": "Кінець глави",
|
"LabelEndOfChapter": "Кінець глави",
|
||||||
"LabelEpisode": "Епізод",
|
"LabelEpisode": "Епізод",
|
||||||
|
"LabelEpisodeNotLinkedToRssFeed": "Епізод не прив'язаний до RSS-каналу",
|
||||||
|
"LabelEpisodeNumber": "Епізод #{0}",
|
||||||
"LabelEpisodeTitle": "Назва епізоду",
|
"LabelEpisodeTitle": "Назва епізоду",
|
||||||
"LabelEpisodeType": "Тип епізоду",
|
"LabelEpisodeType": "Тип епізоду",
|
||||||
|
"LabelEpisodeUrlFromRssFeed": "URL епізоду з RSS-каналу",
|
||||||
|
"LabelEpisodes": "Епізодов",
|
||||||
|
"LabelEpisodic": "Епізодичний",
|
||||||
"LabelExample": "Приклад",
|
"LabelExample": "Приклад",
|
||||||
"LabelExpandSeries": "Розгорнути серії",
|
"LabelExpandSeries": "Розгорнути серії",
|
||||||
|
"LabelExpandSubSeries": "Розгорнути підсерії",
|
||||||
"LabelExplicit": "Відверта",
|
"LabelExplicit": "Відверта",
|
||||||
"LabelExplicitChecked": "Відверта (з прапорцем)",
|
"LabelExplicitChecked": "Відверта (з прапорцем)",
|
||||||
"LabelExplicitUnchecked": "Не відверта (без прапорця)",
|
"LabelExplicitUnchecked": "Не відверта (без прапорця)",
|
||||||
@@ -305,7 +344,9 @@
|
|||||||
"LabelFetchingMetadata": "Отримання метаданих",
|
"LabelFetchingMetadata": "Отримання метаданих",
|
||||||
"LabelFile": "Файл",
|
"LabelFile": "Файл",
|
||||||
"LabelFileBirthtime": "Дата створення",
|
"LabelFileBirthtime": "Дата створення",
|
||||||
|
"LabelFileBornDate": "Народився {0}",
|
||||||
"LabelFileModified": "Дата змінення",
|
"LabelFileModified": "Дата змінення",
|
||||||
|
"LabelFileModifiedDate": "Змінено {0}",
|
||||||
"LabelFilename": "Ім'я файлу",
|
"LabelFilename": "Ім'я файлу",
|
||||||
"LabelFilterByUser": "Фільтрувати за користувачем",
|
"LabelFilterByUser": "Фільтрувати за користувачем",
|
||||||
"LabelFindEpisodes": "Знайти епізоди",
|
"LabelFindEpisodes": "Знайти епізоди",
|
||||||
@@ -319,6 +360,7 @@
|
|||||||
"LabelFontScale": "Розмір шрифту",
|
"LabelFontScale": "Розмір шрифту",
|
||||||
"LabelFontStrikethrough": "Закреслений",
|
"LabelFontStrikethrough": "Закреслений",
|
||||||
"LabelFormat": "Формат",
|
"LabelFormat": "Формат",
|
||||||
|
"LabelFull": "Повний",
|
||||||
"LabelGenre": "Жанр",
|
"LabelGenre": "Жанр",
|
||||||
"LabelGenres": "Жанри",
|
"LabelGenres": "Жанри",
|
||||||
"LabelHardDeleteFile": "Остаточно видалити файл",
|
"LabelHardDeleteFile": "Остаточно видалити файл",
|
||||||
@@ -361,6 +403,7 @@
|
|||||||
"LabelLess": "Менше",
|
"LabelLess": "Менше",
|
||||||
"LabelLibrariesAccessibleToUser": "Бібліотеки, доступні користувачу",
|
"LabelLibrariesAccessibleToUser": "Бібліотеки, доступні користувачу",
|
||||||
"LabelLibrary": "Бібліотека",
|
"LabelLibrary": "Бібліотека",
|
||||||
|
"LabelLibraryFilterSublistEmpty": "Ні {0}",
|
||||||
"LabelLibraryItem": "Елемент бібліотеки",
|
"LabelLibraryItem": "Елемент бібліотеки",
|
||||||
"LabelLibraryName": "Назва бібліотеки",
|
"LabelLibraryName": "Назва бібліотеки",
|
||||||
"LabelLimit": "Обмеження",
|
"LabelLimit": "Обмеження",
|
||||||
@@ -373,6 +416,10 @@
|
|||||||
"LabelLowestPriority": "Найнижчий пріоритет",
|
"LabelLowestPriority": "Найнижчий пріоритет",
|
||||||
"LabelMatchExistingUsersBy": "Шукати наявних користувачів за",
|
"LabelMatchExistingUsersBy": "Шукати наявних користувачів за",
|
||||||
"LabelMatchExistingUsersByDescription": "Використовується для підключення наявних користувачів. Після підключення користувач отримає унікальний id від вашого сервісу SSO",
|
"LabelMatchExistingUsersByDescription": "Використовується для підключення наявних користувачів. Після підключення користувач отримає унікальний id від вашого сервісу SSO",
|
||||||
|
"LabelMaxEpisodesToDownload": "Максимальна кількість епізодів для завантаження. Використовуйте 0 для необмеженої кількості.",
|
||||||
|
"LabelMaxEpisodesToDownloadPerCheck": "Максимальна кількість нових епізодів для завантаження за перевірку",
|
||||||
|
"LabelMaxEpisodesToKeep": "Максимальна кількість епізодів для зберігання",
|
||||||
|
"LabelMaxEpisodesToKeepHelp": "Значення 0 не встановлює обмеження. Після автоматичного завантаження нового епізоду, буде видалено найстаріший епізод, якщо у вас більше ніж X епізодів. Видаляється лише 1 епізод за одне нове завантаження.",
|
||||||
"LabelMediaPlayer": "Програвач медіа",
|
"LabelMediaPlayer": "Програвач медіа",
|
||||||
"LabelMediaType": "Тип медіа",
|
"LabelMediaType": "Тип медіа",
|
||||||
"LabelMetaTag": "Метатег",
|
"LabelMetaTag": "Метатег",
|
||||||
@@ -418,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "Ім'я OpenID claim, що містить список груп користувачів. Зазвичай їх називають <code>групами</code>. <b>Якщо налаштовано</b>, застосунок автоматично призначатиме ролі на основі членства користувача в групах, за умови, що ці групи названі в claim'і без урахування реєстру 'admin', 'user' або 'guest'. Claim мусить містити список, і якщо користувач належить до кількох груп, програма призначить йому роль, що відповідає найвищому рівню доступу. Якщо жодна група не збігається, у доступі буде відмовлено.",
|
"LabelOpenIDGroupClaimDescription": "Ім'я OpenID claim, що містить список груп користувачів. Зазвичай їх називають <code>групами</code>. <b>Якщо налаштовано</b>, застосунок автоматично призначатиме ролі на основі членства користувача в групах, за умови, що ці групи названі в claim'і без урахування реєстру 'admin', 'user' або 'guest'. Claim мусить містити список, і якщо користувач належить до кількох груп, програма призначить йому роль, що відповідає найвищому рівню доступу. Якщо жодна група не збігається, у доступі буде відмовлено.",
|
||||||
"LabelOpenRSSFeed": "Відкрити RSS-канал",
|
"LabelOpenRSSFeed": "Відкрити RSS-канал",
|
||||||
"LabelOverwrite": "Перезаписати",
|
"LabelOverwrite": "Перезаписати",
|
||||||
|
"LabelPaginationPageXOfY": "Сторінка {0} з {1}",
|
||||||
"LabelPassword": "Пароль",
|
"LabelPassword": "Пароль",
|
||||||
"LabelPath": "Шлях",
|
"LabelPath": "Шлях",
|
||||||
"LabelPermanent": "Постійний",
|
"LabelPermanent": "Постійний",
|
||||||
"LabelPermissionsAccessAllLibraries": "Доступ до усіх бібліотек",
|
"LabelPermissionsAccessAllLibraries": "Доступ до усіх бібліотек",
|
||||||
"LabelPermissionsAccessAllTags": "Доступ до усіх міток",
|
"LabelPermissionsAccessAllTags": "Доступ до усіх міток",
|
||||||
"LabelPermissionsAccessExplicitContent": "Доступ до відвертого вмісту",
|
"LabelPermissionsAccessExplicitContent": "Доступ до відвертого вмісту",
|
||||||
|
"LabelPermissionsCreateEreader": "Можна створити читалку",
|
||||||
"LabelPermissionsDelete": "Може видаляти",
|
"LabelPermissionsDelete": "Може видаляти",
|
||||||
"LabelPermissionsDownload": "Може завантажувати",
|
"LabelPermissionsDownload": "Може завантажувати",
|
||||||
"LabelPermissionsUpdate": "Може оновлювати",
|
"LabelPermissionsUpdate": "Може оновлювати",
|
||||||
@@ -431,6 +480,7 @@
|
|||||||
"LabelPersonalYearReview": "Ваші підсумки року ({0})",
|
"LabelPersonalYearReview": "Ваші підсумки року ({0})",
|
||||||
"LabelPhotoPathURL": "Шлях/URL фото",
|
"LabelPhotoPathURL": "Шлях/URL фото",
|
||||||
"LabelPlayMethod": "Метод відтворення",
|
"LabelPlayMethod": "Метод відтворення",
|
||||||
|
"LabelPlayerChapterNumberMarker": "{0} з {1}",
|
||||||
"LabelPlaylists": "Списки відтворення",
|
"LabelPlaylists": "Списки відтворення",
|
||||||
"LabelPodcast": "Подкаст",
|
"LabelPodcast": "Подкаст",
|
||||||
"LabelPodcastSearchRegion": "Регіон пошуку подкасту",
|
"LabelPodcastSearchRegion": "Регіон пошуку подкасту",
|
||||||
@@ -442,8 +492,12 @@
|
|||||||
"LabelPrimaryEbook": "Основна електронна книга",
|
"LabelPrimaryEbook": "Основна електронна книга",
|
||||||
"LabelProgress": "Прогрес",
|
"LabelProgress": "Прогрес",
|
||||||
"LabelProvider": "Джерело",
|
"LabelProvider": "Джерело",
|
||||||
|
"LabelProviderAuthorizationValue": "Значення заголовка авторизації",
|
||||||
"LabelPubDate": "Дата публікації",
|
"LabelPubDate": "Дата публікації",
|
||||||
"LabelPublishYear": "Рік публікації",
|
"LabelPublishYear": "Рік публікації",
|
||||||
|
"LabelPublishedDate": "Опубліковано {0}",
|
||||||
|
"LabelPublishedDecade": "Десятиліття публікації",
|
||||||
|
"LabelPublishedDecades": "Опубліковані десятиліття",
|
||||||
"LabelPublisher": "Видавець",
|
"LabelPublisher": "Видавець",
|
||||||
"LabelPublishers": "Видавці",
|
"LabelPublishers": "Видавці",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "Користувацька електронна адреса власника",
|
"LabelRSSFeedCustomOwnerEmail": "Користувацька електронна адреса власника",
|
||||||
@@ -463,21 +517,28 @@
|
|||||||
"LabelRedo": "Повторити",
|
"LabelRedo": "Повторити",
|
||||||
"LabelRegion": "Регіон",
|
"LabelRegion": "Регіон",
|
||||||
"LabelReleaseDate": "Дата публікації",
|
"LabelReleaseDate": "Дата публікації",
|
||||||
|
"LabelRemoveAllMetadataAbs": "Видалити всі файли metadata.abs",
|
||||||
|
"LabelRemoveAllMetadataJson": "Видалити всі файли metadata.json",
|
||||||
"LabelRemoveCover": "Видалити обкладинку",
|
"LabelRemoveCover": "Видалити обкладинку",
|
||||||
|
"LabelRemoveMetadataFile": "Видалити файли метаданих у папках елементів бібліотеки",
|
||||||
|
"LabelRemoveMetadataFileHelp": "Видалити всі файли metadata.json та metadata.abs у ваших папках {0}.",
|
||||||
"LabelRowsPerPage": "Рядків на сторінку",
|
"LabelRowsPerPage": "Рядків на сторінку",
|
||||||
"LabelSearchTerm": "Пошуковий запит",
|
"LabelSearchTerm": "Пошуковий запит",
|
||||||
"LabelSearchTitle": "Пошук за назвою",
|
"LabelSearchTitle": "Пошук за назвою",
|
||||||
"LabelSearchTitleOrASIN": "Пошук назви або ASIN",
|
"LabelSearchTitleOrASIN": "Пошук назви або ASIN",
|
||||||
"LabelSeason": "Сезон",
|
"LabelSeason": "Сезон",
|
||||||
|
"LabelSeasonNumber": "Сезон #{0}",
|
||||||
"LabelSelectAll": "Вибрати все",
|
"LabelSelectAll": "Вибрати все",
|
||||||
"LabelSelectAllEpisodes": "Вибрати всі серії",
|
"LabelSelectAllEpisodes": "Вибрати всі серії",
|
||||||
"LabelSelectEpisodesShowing": "Обрати показані епізоди: {0}",
|
"LabelSelectEpisodesShowing": "Обрати показані епізоди: {0}",
|
||||||
"LabelSelectUsers": "Вибрати користувачів",
|
"LabelSelectUsers": "Вибрати користувачів",
|
||||||
"LabelSendEbookToDevice": "Надіслати електронну книгу на...",
|
"LabelSendEbookToDevice": "Надіслати електронну книгу на...",
|
||||||
"LabelSequence": "Послідовність",
|
"LabelSequence": "Послідовність",
|
||||||
|
"LabelSerial": "Серійний",
|
||||||
"LabelSeries": "Серії",
|
"LabelSeries": "Серії",
|
||||||
"LabelSeriesName": "Назва серії",
|
"LabelSeriesName": "Назва серії",
|
||||||
"LabelSeriesProgress": "Прогрес серії",
|
"LabelSeriesProgress": "Прогрес серії",
|
||||||
|
"LabelServerLogLevel": "Рівень журналу сервера",
|
||||||
"LabelServerYearReview": "Підсумки року сервера ({0})",
|
"LabelServerYearReview": "Підсумки року сервера ({0})",
|
||||||
"LabelSetEbookAsPrimary": "Зробити основною",
|
"LabelSetEbookAsPrimary": "Зробити основною",
|
||||||
"LabelSetEbookAsSupplementary": "Зробити додатковою",
|
"LabelSetEbookAsSupplementary": "Зробити додатковою",
|
||||||
@@ -502,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "Серії, що містять одну книгу, будуть приховані зі сторінки серій та полиць головної сторінки.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Серії, що містять одну книгу, будуть приховані зі сторінки серій та полиць головної сторінки.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Полиці на головній сторінці",
|
"LabelSettingsHomePageBookshelfView": "Полиці на головній сторінці",
|
||||||
"LabelSettingsLibraryBookshelfView": "Показувати полиці у бібліотеці",
|
"LabelSettingsLibraryBookshelfView": "Показувати полиці у бібліотеці",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Відсоток виконання більше ніж",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Час, що залишився, менше ніж (секунди)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Позначити медіа-елемент як завершений, коли",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропускати попередні книги у Продовжити серії",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропускати попередні книги у Продовжити серії",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Полиця Продовжити серії на головній сторінці показує найпершу непочату книгу з тих серій, у яких ви завершили хоча б одну книгу та не маєте книг у процесі. Якщо увімкнути це налаштування, то серії продовжуватимуться з останньої завершеної книги, а не з першої непочатої.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Полиця Продовжити серії на головній сторінці показує найпершу непочату книгу з тих серій, у яких ви завершили хоча б одну книгу та не маєте книг у процесі. Якщо увімкнути це налаштування, то серії продовжуватимуться з останньої завершеної книги, а не з першої непочатої.",
|
||||||
"LabelSettingsParseSubtitles": "Дістати підзаголовки",
|
"LabelSettingsParseSubtitles": "Дістати підзаголовки",
|
||||||
@@ -566,6 +630,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} хвилини",
|
"LabelTimeDurationXMinutes": "{0} хвилини",
|
||||||
"LabelTimeDurationXSeconds": "{0} секунди",
|
"LabelTimeDurationXSeconds": "{0} секунди",
|
||||||
"LabelTimeInMinutes": "Час у хвилинах",
|
"LabelTimeInMinutes": "Час у хвилинах",
|
||||||
|
"LabelTimeLeft": "{0} залишилось",
|
||||||
"LabelTimeListened": "Часу прослухано",
|
"LabelTimeListened": "Часу прослухано",
|
||||||
"LabelTimeListenedToday": "Сьогодні прослухано",
|
"LabelTimeListenedToday": "Сьогодні прослухано",
|
||||||
"LabelTimeRemaining": "Лишилося: {0}",
|
"LabelTimeRemaining": "Лишилося: {0}",
|
||||||
@@ -573,6 +638,7 @@
|
|||||||
"LabelTitle": "Назва",
|
"LabelTitle": "Назва",
|
||||||
"LabelToolsEmbedMetadata": "Вбудувати метадані",
|
"LabelToolsEmbedMetadata": "Вбудувати метадані",
|
||||||
"LabelToolsEmbedMetadataDescription": "Вбудувати метадані в аудіофайли, включно з обкладинками та главами.",
|
"LabelToolsEmbedMetadataDescription": "Вбудувати метадані в аудіофайли, включно з обкладинками та главами.",
|
||||||
|
"LabelToolsM4bEncoder": "Кодувальник M4B",
|
||||||
"LabelToolsMakeM4b": "Створити M4B-файл аудіокниги",
|
"LabelToolsMakeM4b": "Створити M4B-файл аудіокниги",
|
||||||
"LabelToolsMakeM4bDescription": "Створити .M4B-аудіокнигу з вбудованими метаданими, обкладинкою та главами.",
|
"LabelToolsMakeM4bDescription": "Створити .M4B-аудіокнигу з вбудованими метаданими, обкладинкою та главами.",
|
||||||
"LabelToolsSplitM4b": "Розділити M4B на MP3",
|
"LabelToolsSplitM4b": "Розділити M4B на MP3",
|
||||||
@@ -585,20 +651,25 @@
|
|||||||
"LabelTracksMultiTrack": "Декілька доріжок",
|
"LabelTracksMultiTrack": "Декілька доріжок",
|
||||||
"LabelTracksNone": "Доріжки відсутні",
|
"LabelTracksNone": "Доріжки відсутні",
|
||||||
"LabelTracksSingleTrack": "Одна доріжка",
|
"LabelTracksSingleTrack": "Одна доріжка",
|
||||||
|
"LabelTrailer": "Трейлер",
|
||||||
"LabelType": "Тип",
|
"LabelType": "Тип",
|
||||||
"LabelUnabridged": "Повна",
|
"LabelUnabridged": "Повна",
|
||||||
"LabelUndo": "Скасувати",
|
"LabelUndo": "Скасувати",
|
||||||
"LabelUnknown": "Невідомо",
|
"LabelUnknown": "Невідомо",
|
||||||
|
"LabelUnknownPublishDate": "Невідома дата публікації",
|
||||||
"LabelUpdateCover": "Оновити обкладинку",
|
"LabelUpdateCover": "Оновити обкладинку",
|
||||||
"LabelUpdateCoverHelp": "Дозволити перезапис наявних обкладинок обраних книг після віднайдення",
|
"LabelUpdateCoverHelp": "Дозволити перезапис наявних обкладинок обраних книг після віднайдення",
|
||||||
"LabelUpdateDetails": "Оновити подробиці",
|
"LabelUpdateDetails": "Оновити подробиці",
|
||||||
"LabelUpdateDetailsHelp": "Дозволити перезапис наявних подробиць обраних книг після віднайдення",
|
"LabelUpdateDetailsHelp": "Дозволити перезапис наявних подробиць обраних книг після віднайдення",
|
||||||
"LabelUpdatedAt": "Оновлення",
|
"LabelUpdatedAt": "Оновлення",
|
||||||
"LabelUploaderDragAndDrop": "Перетягніть файли або теки",
|
"LabelUploaderDragAndDrop": "Перетягніть файли або теки",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "Перетягніть і скиньте файли",
|
||||||
"LabelUploaderDropFiles": "Перетягніть файли",
|
"LabelUploaderDropFiles": "Перетягніть файли",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "Автоматично шукати назву, автора та серію",
|
"LabelUploaderItemFetchMetadataHelp": "Автоматично шукати назву, автора та серію",
|
||||||
|
"LabelUseAdvancedOptions": "Використовувати розширені налаштування",
|
||||||
"LabelUseChapterTrack": "Прогрес глави",
|
"LabelUseChapterTrack": "Прогрес глави",
|
||||||
"LabelUseFullTrack": "Використовувати доріжку повністю",
|
"LabelUseFullTrack": "Використовувати доріжку повністю",
|
||||||
|
"LabelUseZeroForUnlimited": "Використовуйте 0 для необмеженої кількості",
|
||||||
"LabelUser": "Користувач",
|
"LabelUser": "Користувач",
|
||||||
"LabelUsername": "Ім’я користувача",
|
"LabelUsername": "Ім’я користувача",
|
||||||
"LabelValue": "Значення",
|
"LabelValue": "Значення",
|
||||||
@@ -608,6 +679,8 @@
|
|||||||
"LabelViewPlayerSettings": "Переглянути налаштування програвача",
|
"LabelViewPlayerSettings": "Переглянути налаштування програвача",
|
||||||
"LabelViewQueue": "Переглянути чергу відтворення",
|
"LabelViewQueue": "Переглянути чергу відтворення",
|
||||||
"LabelVolume": "Гучність",
|
"LabelVolume": "Гучність",
|
||||||
|
"LabelWebRedirectURLsDescription": "Авторизуйте ці URL у вашому OAuth постачальнику, щоб дозволити редирекцію назад до веб-додатку після входу:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "Підпапка для Redirect URL",
|
||||||
"LabelWeekdaysToRun": "Виконувати у дні",
|
"LabelWeekdaysToRun": "Виконувати у дні",
|
||||||
"LabelXBooks": "{0} книг",
|
"LabelXBooks": "{0} книг",
|
||||||
"LabelXItems": "{0} елементів",
|
"LabelXItems": "{0} елементів",
|
||||||
@@ -637,19 +710,27 @@
|
|||||||
"MessageCheckingCron": "Перевірка планувальника...",
|
"MessageCheckingCron": "Перевірка планувальника...",
|
||||||
"MessageConfirmCloseFeed": "Ви дійсно бажаєте закрити цей канал?",
|
"MessageConfirmCloseFeed": "Ви дійсно бажаєте закрити цей канал?",
|
||||||
"MessageConfirmDeleteBackup": "Ви дійсно бажаєте видалити резервну копію за {0}?",
|
"MessageConfirmDeleteBackup": "Ви дійсно бажаєте видалити резервну копію за {0}?",
|
||||||
|
"MessageConfirmDeleteDevice": "Ви впевнені, що хочете видалити пристрій для читання \"{0}\"?",
|
||||||
"MessageConfirmDeleteFile": "Файл буде видалено з вашої файлової системи. Ви впевнені?",
|
"MessageConfirmDeleteFile": "Файл буде видалено з вашої файлової системи. Ви впевнені?",
|
||||||
"MessageConfirmDeleteLibrary": "Ви дійсно бажаєте назавжди видалити бібліотеку \"{0}\"?",
|
"MessageConfirmDeleteLibrary": "Ви дійсно бажаєте назавжди видалити бібліотеку \"{0}\"?",
|
||||||
"MessageConfirmDeleteLibraryItem": "Елемент бібліотеки буде видалено з бази даних та вашої файлової системи. Ви впевнені?",
|
"MessageConfirmDeleteLibraryItem": "Елемент бібліотеки буде видалено з бази даних та вашої файлової системи. Ви впевнені?",
|
||||||
"MessageConfirmDeleteLibraryItems": "З бази даних та вашої файлової системи будуть видалені елементи бібліотеки: {0}. Ви впевнені?",
|
"MessageConfirmDeleteLibraryItems": "З бази даних та вашої файлової системи будуть видалені елементи бібліотеки: {0}. Ви впевнені?",
|
||||||
|
"MessageConfirmDeleteMetadataProvider": "Ви впевнені, що хочете видалити користувацького постачальника метаданих \"{0}\"?",
|
||||||
|
"MessageConfirmDeleteNotification": "Ви впевнені, що хочете видалити це сповіщення?",
|
||||||
"MessageConfirmDeleteSession": "Ви дійсно бажаєте видалити цей сеанс?",
|
"MessageConfirmDeleteSession": "Ви дійсно бажаєте видалити цей сеанс?",
|
||||||
|
"MessageConfirmEmbedMetadataInAudioFiles": "Ви впевнені, що хочете вставити метадані в {0} аудіофайлів?",
|
||||||
"MessageConfirmForceReScan": "Ви дійсно бажаєте примусово пересканувати?",
|
"MessageConfirmForceReScan": "Ви дійсно бажаєте примусово пересканувати?",
|
||||||
"MessageConfirmMarkAllEpisodesFinished": "Ви дійсно бажаєте позначити усі епізоди завершеними?",
|
"MessageConfirmMarkAllEpisodesFinished": "Ви дійсно бажаєте позначити усі епізоди завершеними?",
|
||||||
"MessageConfirmMarkAllEpisodesNotFinished": "Ви дійсно бажаєте позначити усі епізоди незавершеними?",
|
"MessageConfirmMarkAllEpisodesNotFinished": "Ви дійсно бажаєте позначити усі епізоди незавершеними?",
|
||||||
|
"MessageConfirmMarkItemFinished": "Ви впевнені, що хочете позначити \"{0}\" як завершене?",
|
||||||
|
"MessageConfirmMarkItemNotFinished": "Ви впевнені, що хочете позначити \"{0}\" як незавершене?",
|
||||||
"MessageConfirmMarkSeriesFinished": "Ви дійсно бажаєте позначити усі книги серії завершеними?",
|
"MessageConfirmMarkSeriesFinished": "Ви дійсно бажаєте позначити усі книги серії завершеними?",
|
||||||
"MessageConfirmMarkSeriesNotFinished": "Ви дійсно бажаєте позначити всі книги серії незавершеними?",
|
"MessageConfirmMarkSeriesNotFinished": "Ви дійсно бажаєте позначити всі книги серії незавершеними?",
|
||||||
|
"MessageConfirmNotificationTestTrigger": "Активувати це сповіщення з тестовими даними?",
|
||||||
"MessageConfirmPurgeCache": "Очищення кешу видалить усю теку <code>/metadata/cache</code>. <br /><br />Ви дійсно бажаєте видалити теку кешу?",
|
"MessageConfirmPurgeCache": "Очищення кешу видалить усю теку <code>/metadata/cache</code>. <br /><br />Ви дійсно бажаєте видалити теку кешу?",
|
||||||
"MessageConfirmPurgeItemsCache": "Очищення кешу елементів видалить усю теку <code>/metadata/cache/items</code>. <br />Ви певні?",
|
"MessageConfirmPurgeItemsCache": "Очищення кешу елементів видалить усю теку <code>/metadata/cache/items</code>. <br />Ви певні?",
|
||||||
"MessageConfirmQuickEmbed": "Увага! Швидке вбудування не створює резервних копій ваших аудіо. Переконайтеся, що маєте копію ваших файлів.<br><br>Продовжити?",
|
"MessageConfirmQuickEmbed": "Увага! Швидке вбудування не створює резервних копій ваших аудіо. Переконайтеся, що маєте копію ваших файлів.<br><br>Продовжити?",
|
||||||
|
"MessageConfirmQuickMatchEpisodes": "При виявленні співпадінь інформація про епізоди швидкого пошуку буде перезаписана. Будуть оновлені тільки несуперечливі епізоди. Ви впевнені?",
|
||||||
"MessageConfirmReScanLibraryItems": "Ви дійсно бажаєте пересканувати елементи: {0}?",
|
"MessageConfirmReScanLibraryItems": "Ви дійсно бажаєте пересканувати елементи: {0}?",
|
||||||
"MessageConfirmRemoveAllChapters": "Ви дійсно бажаєте видалити усі глави?",
|
"MessageConfirmRemoveAllChapters": "Ви дійсно бажаєте видалити усі глави?",
|
||||||
"MessageConfirmRemoveAuthor": "Ви дійсно бажаєте видалити автора \"{0}\"?",
|
"MessageConfirmRemoveAuthor": "Ви дійсно бажаєте видалити автора \"{0}\"?",
|
||||||
@@ -657,6 +738,7 @@
|
|||||||
"MessageConfirmRemoveEpisode": "Ви дійсно бажаєте видалити епізод \"{0}\"?",
|
"MessageConfirmRemoveEpisode": "Ви дійсно бажаєте видалити епізод \"{0}\"?",
|
||||||
"MessageConfirmRemoveEpisodes": "Ви дійсно бажаєте видалити епізодів: {0}?",
|
"MessageConfirmRemoveEpisodes": "Ви дійсно бажаєте видалити епізодів: {0}?",
|
||||||
"MessageConfirmRemoveListeningSessions": "Ви дійсно бажаєте видалити сеанси прослуховування: {0}?",
|
"MessageConfirmRemoveListeningSessions": "Ви дійсно бажаєте видалити сеанси прослуховування: {0}?",
|
||||||
|
"MessageConfirmRemoveMetadataFiles": "Ви впевнені, що хочете видалити всі файли metadata.{0} у папках елементів вашої бібліотеки?",
|
||||||
"MessageConfirmRemoveNarrator": "Ви дійсно бажаєте видалити читця \"{0}\"?",
|
"MessageConfirmRemoveNarrator": "Ви дійсно бажаєте видалити читця \"{0}\"?",
|
||||||
"MessageConfirmRemovePlaylist": "Ви дійсно бажаєте видалити список відтворення \"{0}\"?",
|
"MessageConfirmRemovePlaylist": "Ви дійсно бажаєте видалити список відтворення \"{0}\"?",
|
||||||
"MessageConfirmRenameGenre": "Ви дійсно бажаєте замінити жанр \"{0}\" на \"{1}\" для усіх елементів?",
|
"MessageConfirmRenameGenre": "Ви дійсно бажаєте замінити жанр \"{0}\" на \"{1}\" для усіх елементів?",
|
||||||
@@ -665,11 +747,14 @@
|
|||||||
"MessageConfirmRenameTag": "Ви дійсно бажаєте замінити мітку \"{0}\" на \"{1}\" для усіх елементів?",
|
"MessageConfirmRenameTag": "Ви дійсно бажаєте замінити мітку \"{0}\" на \"{1}\" для усіх елементів?",
|
||||||
"MessageConfirmRenameTagMergeNote": "Примітка: така мітка вже існує, тож їх буде об'єднано.",
|
"MessageConfirmRenameTagMergeNote": "Примітка: така мітка вже існує, тож їх буде об'єднано.",
|
||||||
"MessageConfirmRenameTagWarning": "Увага! Вже існує схожа мітка у іншому регістрі \"{0}\".",
|
"MessageConfirmRenameTagWarning": "Увага! Вже існує схожа мітка у іншому регістрі \"{0}\".",
|
||||||
|
"MessageConfirmResetProgress": "Ви впевнені, що хочете скинути свій прогрес?",
|
||||||
"MessageConfirmSendEbookToDevice": "Ви дійсно хочете відправити на пристрій \"{2}\" електроні книги: {0}, \"{1}\"?",
|
"MessageConfirmSendEbookToDevice": "Ви дійсно хочете відправити на пристрій \"{2}\" електроні книги: {0}, \"{1}\"?",
|
||||||
|
"MessageConfirmUnlinkOpenId": "Ви впевнені, що хочете відв'язати цього користувача від OpenID?",
|
||||||
"MessageDownloadingEpisode": "Завантаження епізоду",
|
"MessageDownloadingEpisode": "Завантаження епізоду",
|
||||||
"MessageDragFilesIntoTrackOrder": "Перетягніть файли до правильного порядку",
|
"MessageDragFilesIntoTrackOrder": "Перетягніть файли до правильного порядку",
|
||||||
"MessageEmbedFailed": "Не вдалося вбудувати!",
|
"MessageEmbedFailed": "Не вдалося вбудувати!",
|
||||||
"MessageEmbedFinished": "Вбудовано!",
|
"MessageEmbedFinished": "Вбудовано!",
|
||||||
|
"MessageEmbedQueue": "В черзі на вбудовування метаданих ({0} в черзі)",
|
||||||
"MessageEpisodesQueuedForDownload": "Епізодів у черзі завантаження: {0}",
|
"MessageEpisodesQueuedForDownload": "Епізодів у черзі завантаження: {0}",
|
||||||
"MessageEreaderDevices": "Аби гарантувати отримання електронних книг, вам може знадобитися додати вказану вище адресу електронної пошти як правильного відправника на кожному з пристроїв зі списку нижче.",
|
"MessageEreaderDevices": "Аби гарантувати отримання електронних книг, вам може знадобитися додати вказану вище адресу електронної пошти як правильного відправника на кожному з пристроїв зі списку нижче.",
|
||||||
"MessageFeedURLWillBe": "URL-адреса каналу буде {0}",
|
"MessageFeedURLWillBe": "URL-адреса каналу буде {0}",
|
||||||
@@ -700,6 +785,7 @@
|
|||||||
"MessageNoCollections": "Добірки відсутні",
|
"MessageNoCollections": "Добірки відсутні",
|
||||||
"MessageNoCoversFound": "Обкладинок не знайдено",
|
"MessageNoCoversFound": "Обкладинок не знайдено",
|
||||||
"MessageNoDescription": "Без опису",
|
"MessageNoDescription": "Без опису",
|
||||||
|
"MessageNoDevices": "Немає пристроїв",
|
||||||
"MessageNoDownloadsInProgress": "Немає активних завантажень",
|
"MessageNoDownloadsInProgress": "Немає активних завантажень",
|
||||||
"MessageNoDownloadsQueued": "Немає завантажень у черзі",
|
"MessageNoDownloadsQueued": "Немає завантажень у черзі",
|
||||||
"MessageNoEpisodeMatchesFound": "Відповідних епізодів не знайдено",
|
"MessageNoEpisodeMatchesFound": "Відповідних епізодів не знайдено",
|
||||||
@@ -713,6 +799,7 @@
|
|||||||
"MessageNoLogs": "Журнал порожній",
|
"MessageNoLogs": "Журнал порожній",
|
||||||
"MessageNoMediaProgress": "Прогрес відсутній",
|
"MessageNoMediaProgress": "Прогрес відсутній",
|
||||||
"MessageNoNotifications": "Сповіщення відсутні",
|
"MessageNoNotifications": "Сповіщення відсутні",
|
||||||
|
"MessageNoPodcastFeed": "Невірний подкаст: Немає каналу",
|
||||||
"MessageNoPodcastsFound": "Подкастів не знайдено",
|
"MessageNoPodcastsFound": "Подкастів не знайдено",
|
||||||
"MessageNoResults": "Немає результатів",
|
"MessageNoResults": "Немає результатів",
|
||||||
"MessageNoSearchResultsFor": "Немає результатів пошуку для \"{0}\"",
|
"MessageNoSearchResultsFor": "Немає результатів пошуку для \"{0}\"",
|
||||||
@@ -727,7 +814,12 @@
|
|||||||
"MessagePauseChapter": "Призупинити відтворення глави",
|
"MessagePauseChapter": "Призупинити відтворення глави",
|
||||||
"MessagePlayChapter": "Слухати початок глави",
|
"MessagePlayChapter": "Слухати початок глави",
|
||||||
"MessagePlaylistCreateFromCollection": "Створити список відтворення з добірки",
|
"MessagePlaylistCreateFromCollection": "Створити список відтворення з добірки",
|
||||||
|
"MessagePleaseWait": "Будь ласка, зачекайте...",
|
||||||
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не має RSS-каналу для пошуку",
|
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не має RSS-каналу для пошуку",
|
||||||
|
"MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки",
|
||||||
|
"MessageQuickEmbedInProgress": "Швидке вбудовування в процесі",
|
||||||
|
"MessageQuickEmbedQueue": "В черзі на швидке вбудовування ({0} в черзі)",
|
||||||
|
"MessageQuickMatchAllEpisodes": "Швидке співставлення всіх епізодів",
|
||||||
"MessageQuickMatchDescription": "Заповнити відсутні подробиці та обкладинку першим результатом пошуку '{0}'. Не перезаписує подробиці, якщо не увімкнено параметр \"Надавати перевагу віднайденим метаданим\".",
|
"MessageQuickMatchDescription": "Заповнити відсутні подробиці та обкладинку першим результатом пошуку '{0}'. Не перезаписує подробиці, якщо не увімкнено параметр \"Надавати перевагу віднайденим метаданим\".",
|
||||||
"MessageRemoveChapter": "Видалити главу",
|
"MessageRemoveChapter": "Видалити главу",
|
||||||
"MessageRemoveEpisodes": "Видалити епізодів: {0}",
|
"MessageRemoveEpisodes": "Видалити епізодів: {0}",
|
||||||
@@ -745,6 +837,41 @@
|
|||||||
"MessageShareExpiresIn": "Сплине за {0}",
|
"MessageShareExpiresIn": "Сплине за {0}",
|
||||||
"MessageShareURLWillBe": "Поширюваний URL - <strong>{0}</strong>",
|
"MessageShareURLWillBe": "Поширюваний URL - <strong>{0}</strong>",
|
||||||
"MessageStartPlaybackAtTime": "Почати відтворення \"{0}\" з {1}?",
|
"MessageStartPlaybackAtTime": "Почати відтворення \"{0}\" з {1}?",
|
||||||
|
"MessageTaskAudioFileNotWritable": "Аудіофайл \"{0}\" недоступний для запису",
|
||||||
|
"MessageTaskCanceledByUser": "Задача скасована користувачем",
|
||||||
|
"MessageTaskDownloadingEpisodeDescription": "Завантаження епізоду \"{0}\"",
|
||||||
|
"MessageTaskEmbeddingMetadata": "Вбудовування метаданих",
|
||||||
|
"MessageTaskEmbeddingMetadataDescription": "Вбудовування метаданих у аудіокнигу \"{0}\"",
|
||||||
|
"MessageTaskEncodingM4b": "Кодування M4B",
|
||||||
|
"MessageTaskEncodingM4bDescription": "Кодування аудіокниги \"{0}\" в один файл m4b",
|
||||||
|
"MessageTaskFailed": "Неуспішно",
|
||||||
|
"MessageTaskFailedToBackupAudioFile": "Не вдалося створити резервну копію аудіофайлу \"{0}\"",
|
||||||
|
"MessageTaskFailedToCreateCacheDirectory": "Не вдалося створити каталог кешу",
|
||||||
|
"MessageTaskFailedToEmbedMetadataInFile": "Не вдалося вбудувати метадані у файл \"{0}\"",
|
||||||
|
"MessageTaskFailedToMergeAudioFiles": "Не вдалося об’єднати аудіофайли",
|
||||||
|
"MessageTaskFailedToMoveM4bFile": "Не вдалося перемістити файл m4b",
|
||||||
|
"MessageTaskFailedToWriteMetadataFile": "Не вдалося записати файл метаданих",
|
||||||
|
"MessageTaskMatchingBooksInLibrary": "Відповідність книг у бібліотеці \"{0}\"",
|
||||||
|
"MessageTaskNoFilesToScan": "Немає файлів для сканування",
|
||||||
|
"MessageTaskOpmlImport": "Імпорт OPML",
|
||||||
|
"MessageTaskOpmlImportDescription": "Створення подкастів з {0} RSS-стрічок",
|
||||||
|
"MessageTaskOpmlImportFeed": "Канал імпорту OPML",
|
||||||
|
"MessageTaskOpmlImportFeedDescription": "Імпорт RSS-каналу \"{0}\"",
|
||||||
|
"MessageTaskOpmlImportFeedFailed": "Не вдалося отримати подкаст-стрічку",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastDescription": "Створення подкасту \"{0}\"",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastExists": "Подкаст вже існує за цим шляхом",
|
||||||
|
"MessageTaskOpmlImportFeedPodcastFailed": "Не вдалося створити подкаст",
|
||||||
|
"MessageTaskOpmlImportFinished": "Додано {0} подкастів",
|
||||||
|
"MessageTaskOpmlParseFailed": "Не вдалося розібрати файл OPML",
|
||||||
|
"MessageTaskOpmlParseFastFail": "Невірний файл OPML: не знайдено тег <opml> або тег <outline>",
|
||||||
|
"MessageTaskOpmlParseNoneFound": "У файлі OPML не знайдено жодного канала",
|
||||||
|
"MessageTaskScanItemsAdded": "{0} додано",
|
||||||
|
"MessageTaskScanItemsMissing": "{0} відсутній",
|
||||||
|
"MessageTaskScanItemsUpdated": "{0} оновлено",
|
||||||
|
"MessageTaskScanNoChangesNeeded": "Змін не потрібно",
|
||||||
|
"MessageTaskScanningFileChanges": "Сканування змін файлів у \"{0}\"",
|
||||||
|
"MessageTaskScanningLibrary": "Сканування бібліотеки \"{0}\"",
|
||||||
|
"MessageTaskTargetDirectoryNotWritable": "Цільовий каталог недоступний для запису",
|
||||||
"MessageThinking": "Думаю…",
|
"MessageThinking": "Думаю…",
|
||||||
"MessageUploaderItemFailed": "Не вдалося завантажити",
|
"MessageUploaderItemFailed": "Не вдалося завантажити",
|
||||||
"MessageUploaderItemSuccess": "Успішно завантажено!",
|
"MessageUploaderItemSuccess": "Успішно завантажено!",
|
||||||
@@ -762,6 +889,10 @@
|
|||||||
"NoteUploaderFoldersWithMediaFiles": "Теки з медіафайлами буде оброблено як окремі елементи бібліотеки.",
|
"NoteUploaderFoldersWithMediaFiles": "Теки з медіафайлами буде оброблено як окремі елементи бібліотеки.",
|
||||||
"NoteUploaderOnlyAudioFiles": "Якщо завантажувати лише аудіофайли, то кожен файл буде оброблено як окрему книгу.",
|
"NoteUploaderOnlyAudioFiles": "Якщо завантажувати лише аудіофайли, то кожен файл буде оброблено як окрему книгу.",
|
||||||
"NoteUploaderUnsupportedFiles": "Непідтримувані файли пропущено. Під час вибору або перетягування теки, файли, що знаходяться поза текою, пропускаються.",
|
"NoteUploaderUnsupportedFiles": "Непідтримувані файли пропущено. Під час вибору або перетягування теки, файли, що знаходяться поза текою, пропускаються.",
|
||||||
|
"NotificationOnBackupCompletedDescription": "Запускається після завершення резервного копіювання",
|
||||||
|
"NotificationOnBackupFailedDescription": "Срабатывает при збої резервного копіювання",
|
||||||
|
"NotificationOnEpisodeDownloadedDescription": "Запускається при автоматичному завантаженні епізоду подкасту",
|
||||||
|
"NotificationOnTestDescription": "Подія для тестування системи сповіщень",
|
||||||
"PlaceholderNewCollection": "Нова назва добірки",
|
"PlaceholderNewCollection": "Нова назва добірки",
|
||||||
"PlaceholderNewFolderPath": "Новий шлях до теки",
|
"PlaceholderNewFolderPath": "Новий шлях до теки",
|
||||||
"PlaceholderNewPlaylist": "Нова назва списку",
|
"PlaceholderNewPlaylist": "Нова назва списку",
|
||||||
@@ -786,17 +917,29 @@
|
|||||||
"StatsTotalDuration": "Загальною довжиною…",
|
"StatsTotalDuration": "Загальною довжиною…",
|
||||||
"StatsYearInReview": "ОГЛЯД РОКУ",
|
"StatsYearInReview": "ОГЛЯД РОКУ",
|
||||||
"ToastAccountUpdateSuccess": "Профіль оновлено",
|
"ToastAccountUpdateSuccess": "Профіль оновлено",
|
||||||
|
"ToastAppriseUrlRequired": "Необхідно ввести URL для Apprise",
|
||||||
|
"ToastAsinRequired": "ASIN є обов'язковим",
|
||||||
"ToastAuthorImageRemoveSuccess": "Фото автора видалено",
|
"ToastAuthorImageRemoveSuccess": "Фото автора видалено",
|
||||||
|
"ToastAuthorNotFound": "Автор \"{0}\" не знайдений",
|
||||||
|
"ToastAuthorRemoveSuccess": "Автор видалений",
|
||||||
|
"ToastAuthorSearchNotFound": "Автор не знайдений",
|
||||||
"ToastAuthorUpdateMerged": "Автора об'єднано",
|
"ToastAuthorUpdateMerged": "Автора об'єднано",
|
||||||
"ToastAuthorUpdateSuccess": "Автора оновлено",
|
"ToastAuthorUpdateSuccess": "Автора оновлено",
|
||||||
"ToastAuthorUpdateSuccessNoImageFound": "Автора оновлено (фото не знайдено)",
|
"ToastAuthorUpdateSuccessNoImageFound": "Автора оновлено (фото не знайдено)",
|
||||||
|
"ToastBackupAppliedSuccess": "Резервна копія застосована",
|
||||||
"ToastBackupCreateFailed": "Не вдалося створити резервну копію",
|
"ToastBackupCreateFailed": "Не вдалося створити резервну копію",
|
||||||
"ToastBackupCreateSuccess": "Резервну копію створено",
|
"ToastBackupCreateSuccess": "Резервну копію створено",
|
||||||
"ToastBackupDeleteFailed": "Не вдалося видалити резервну копію",
|
"ToastBackupDeleteFailed": "Не вдалося видалити резервну копію",
|
||||||
"ToastBackupDeleteSuccess": "Резервну копію видалено",
|
"ToastBackupDeleteSuccess": "Резервну копію видалено",
|
||||||
|
"ToastBackupInvalidMaxKeep": "Профіль оновленоПрофіль оновлено",
|
||||||
|
"ToastBackupInvalidMaxSize": "Невірний максимальний розмір резервної копії",
|
||||||
"ToastBackupRestoreFailed": "Не вдалося відновити резервну копію",
|
"ToastBackupRestoreFailed": "Не вдалося відновити резервну копію",
|
||||||
"ToastBackupUploadFailed": "Не вдалося завантажити резервну копію",
|
"ToastBackupUploadFailed": "Не вдалося завантажити резервну копію",
|
||||||
"ToastBackupUploadSuccess": "Резервну копію завантажено",
|
"ToastBackupUploadSuccess": "Резервну копію завантажено",
|
||||||
|
"ToastBatchDeleteFailed": "Помилка при пакетному видаленні",
|
||||||
|
"ToastBatchDeleteSuccess": "Пакетне видалення успішне",
|
||||||
|
"ToastBatchQuickMatchFailed": "Не вдалося виконати пакетне швидке співпадіння!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Пакетне швидке співпадіння {0} книг розпочато!",
|
||||||
"ToastBatchUpdateFailed": "Не вдалося оновити обрані",
|
"ToastBatchUpdateFailed": "Не вдалося оновити обрані",
|
||||||
"ToastBatchUpdateSuccess": "Обрані успішно оновлено",
|
"ToastBatchUpdateSuccess": "Обрані успішно оновлено",
|
||||||
"ToastBookmarkCreateFailed": "Не вдалося створити закладку",
|
"ToastBookmarkCreateFailed": "Не вдалося створити закладку",
|
||||||
@@ -807,19 +950,43 @@
|
|||||||
"ToastCachePurgeSuccess": "Кеш очищено",
|
"ToastCachePurgeSuccess": "Кеш очищено",
|
||||||
"ToastChaptersHaveErrors": "Глави містять помилки",
|
"ToastChaptersHaveErrors": "Глави містять помилки",
|
||||||
"ToastChaptersMustHaveTitles": "Глави повинні мати назви",
|
"ToastChaptersMustHaveTitles": "Глави повинні мати назви",
|
||||||
|
"ToastChaptersRemoved": "Розділи видалені",
|
||||||
|
"ToastChaptersUpdated": "Розділи оновлені",
|
||||||
|
"ToastCollectionItemsAddFailed": "Не вдалося додати елемент(и) до колекції",
|
||||||
|
"ToastCollectionItemsAddSuccess": "Елемент(и) успішно додано до колекції",
|
||||||
"ToastCollectionItemsRemoveSuccess": "Елемент(и) видалено з добірки",
|
"ToastCollectionItemsRemoveSuccess": "Елемент(и) видалено з добірки",
|
||||||
"ToastCollectionRemoveSuccess": "Добірку видалено",
|
"ToastCollectionRemoveSuccess": "Добірку видалено",
|
||||||
"ToastCollectionUpdateSuccess": "Добірку оновлено",
|
"ToastCollectionUpdateSuccess": "Добірку оновлено",
|
||||||
|
"ToastCoverUpdateFailed": "Не вдалося оновити обкладинку",
|
||||||
"ToastDeleteFileFailed": "Не вдалося видалити файл",
|
"ToastDeleteFileFailed": "Не вдалося видалити файл",
|
||||||
"ToastDeleteFileSuccess": "Файл видалено",
|
"ToastDeleteFileSuccess": "Файл видалено",
|
||||||
|
"ToastDeviceAddFailed": "Не вдалося додати пристрій",
|
||||||
|
"ToastDeviceNameAlreadyExists": "Пристрій для електронних книг з таким ім'ям вже існує",
|
||||||
|
"ToastDeviceTestEmailFailed": "Не вдалося надіслати тестовий електронний лист",
|
||||||
|
"ToastDeviceTestEmailSuccess": "Тестовий електронний лист надіслано",
|
||||||
|
"ToastEmailSettingsUpdateSuccess": "Налаштування електронної пошти оновлено",
|
||||||
|
"ToastEncodeCancelFailed": "Не вдалося скасувати кодування",
|
||||||
|
"ToastEncodeCancelSucces": "Кодування скасовано",
|
||||||
|
"ToastEpisodeDownloadQueueClearFailed": "Не вдалося очистити чергу",
|
||||||
|
"ToastEpisodeDownloadQueueClearSuccess": "Чергу на завантаження епізодів очищено",
|
||||||
|
"ToastEpisodeUpdateSuccess": "{0} епізодів оновлено",
|
||||||
"ToastErrorCannotShare": "Не можна типово поширити на цей пристрій",
|
"ToastErrorCannotShare": "Не можна типово поширити на цей пристрій",
|
||||||
"ToastFailedToLoadData": "Не вдалося завантажити дані",
|
"ToastFailedToLoadData": "Не вдалося завантажити дані",
|
||||||
|
"ToastFailedToMatch": "Не вдалося знайти відповідність",
|
||||||
|
"ToastFailedToShare": "Не вдалося поділитися",
|
||||||
|
"ToastFailedToUpdate": "Не вдалося оновити",
|
||||||
|
"ToastInvalidImageUrl": "Невірний URL зображення",
|
||||||
|
"ToastInvalidMaxEpisodesToDownload": "Невірна кількість епізодів для завантаження",
|
||||||
|
"ToastInvalidUrl": "Невірний URL",
|
||||||
"ToastItemCoverUpdateSuccess": "Обкладинку елемента оновлено",
|
"ToastItemCoverUpdateSuccess": "Обкладинку елемента оновлено",
|
||||||
|
"ToastItemDeletedFailed": "Не вдалося видалити елемент",
|
||||||
|
"ToastItemDeletedSuccess": "Видалений елемент",
|
||||||
"ToastItemDetailsUpdateSuccess": "Подробиці про елемент оновлено",
|
"ToastItemDetailsUpdateSuccess": "Подробиці про елемент оновлено",
|
||||||
"ToastItemMarkedAsFinishedFailed": "Не вдалося позначити як завершене",
|
"ToastItemMarkedAsFinishedFailed": "Не вдалося позначити як завершене",
|
||||||
"ToastItemMarkedAsFinishedSuccess": "Елемент позначено як завершений",
|
"ToastItemMarkedAsFinishedSuccess": "Елемент позначено як завершений",
|
||||||
"ToastItemMarkedAsNotFinishedFailed": "Не вдалося позначити незавершеним",
|
"ToastItemMarkedAsNotFinishedFailed": "Не вдалося позначити незавершеним",
|
||||||
"ToastItemMarkedAsNotFinishedSuccess": "Елемент позначено незавершеним",
|
"ToastItemMarkedAsNotFinishedSuccess": "Елемент позначено незавершеним",
|
||||||
|
"ToastItemUpdateSuccess": "Елемент оновлено",
|
||||||
"ToastLibraryCreateFailed": "Не вдалося створити бібліотеку",
|
"ToastLibraryCreateFailed": "Не вдалося створити бібліотеку",
|
||||||
"ToastLibraryCreateSuccess": "Бібліотеку \"{0}\" створено",
|
"ToastLibraryCreateSuccess": "Бібліотеку \"{0}\" створено",
|
||||||
"ToastLibraryDeleteFailed": "Не вдалося видалити бібліотеку",
|
"ToastLibraryDeleteFailed": "Не вдалося видалити бібліотеку",
|
||||||
@@ -827,28 +994,83 @@
|
|||||||
"ToastLibraryScanFailedToStart": "Не вдалося розпочати сканування",
|
"ToastLibraryScanFailedToStart": "Не вдалося розпочати сканування",
|
||||||
"ToastLibraryScanStarted": "Почалося сканування бібліотеки",
|
"ToastLibraryScanStarted": "Почалося сканування бібліотеки",
|
||||||
"ToastLibraryUpdateSuccess": "Бібліотеку \"{0}\" оновлено",
|
"ToastLibraryUpdateSuccess": "Бібліотеку \"{0}\" оновлено",
|
||||||
|
"ToastMatchAllAuthorsFailed": "Не вдалось знайти відповідності з усіма авторами",
|
||||||
|
"ToastMetadataFilesRemovedError": "Помилка при видаленні metadata.{0} файли",
|
||||||
|
"ToastMetadataFilesRemovedNoneFound": "У бібліотеці не знайдено metadata.{0} файлів",
|
||||||
|
"ToastMetadataFilesRemovedNoneRemoved": "Не видалено metadata.{0} файлів",
|
||||||
|
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} файлів видалено",
|
||||||
|
"ToastMustHaveAtLeastOnePath": "Повинен бути хоча б один шлях",
|
||||||
|
"ToastNameEmailRequired": "Ім'я та електронна пошта обов'язкові",
|
||||||
|
"ToastNameRequired": "Ім'я обов'язкове",
|
||||||
|
"ToastNewEpisodesFound": "{0} нових епізодів знайдено",
|
||||||
|
"ToastNewUserCreatedFailed": "Не вдалося створити акаунт: \"{0}\"",
|
||||||
|
"ToastNewUserCreatedSuccess": "Новий акаунт створено",
|
||||||
|
"ToastNewUserLibraryError": "Потрібно вибрати хоча б одну бібліотеку",
|
||||||
|
"ToastNewUserPasswordError": "Пароль обов'язковий, лише користувач з правами root може мати порожній пароль",
|
||||||
|
"ToastNewUserTagError": "Потрібно вибрати хоча б один тег",
|
||||||
|
"ToastNewUserUsernameError": "Введіть ім'я користувача",
|
||||||
|
"ToastNoNewEpisodesFound": "Нових епізодів не знайдено",
|
||||||
|
"ToastNoUpdatesNecessary": "Оновлення не потрібні",
|
||||||
|
"ToastNotificationCreateFailed": "Не вдалося створити сповіщення",
|
||||||
|
"ToastNotificationDeleteFailed": "Не вдалося видалити сповіщення",
|
||||||
|
"ToastNotificationFailedMaximum": "Максимальна кількість невдалих спроб повинна бути >= 0",
|
||||||
|
"ToastNotificationQueueMaximum": "Максимальна кількість сповіщень у черзі повинна бути >= 0",
|
||||||
|
"ToastNotificationSettingsUpdateSuccess": "Налаштування сповіщень оновлено",
|
||||||
|
"ToastNotificationTestTriggerFailed": "Не вдалося ініціювати тестове сповіщення",
|
||||||
|
"ToastNotificationTestTriggerSuccess": "Спрацьовувало сповіщення про тестування",
|
||||||
|
"ToastNotificationUpdateSuccess": "Сповіщення оновлено",
|
||||||
"ToastPlaylistCreateFailed": "Не вдалося створити список",
|
"ToastPlaylistCreateFailed": "Не вдалося створити список",
|
||||||
"ToastPlaylistCreateSuccess": "Список відтворення створено",
|
"ToastPlaylistCreateSuccess": "Список відтворення створено",
|
||||||
"ToastPlaylistRemoveSuccess": "Список відтворення видалено",
|
"ToastPlaylistRemoveSuccess": "Список відтворення видалено",
|
||||||
"ToastPlaylistUpdateSuccess": "Список відтворення оновлено",
|
"ToastPlaylistUpdateSuccess": "Список відтворення оновлено",
|
||||||
"ToastPodcastCreateFailed": "Не вдалося створити подкаст",
|
"ToastPodcastCreateFailed": "Не вдалося створити подкаст",
|
||||||
"ToastPodcastCreateSuccess": "Подкаст успішно створено",
|
"ToastPodcastCreateSuccess": "Подкаст успішно створено",
|
||||||
|
"ToastPodcastGetFeedFailed": "Не вдалося отримати фід подкасту",
|
||||||
|
"ToastPodcastNoEpisodesInFeed": "У RSS-каналі не знайдено епізодів",
|
||||||
|
"ToastPodcastNoRssFeed": "Подкаст не має RSS-каналу",
|
||||||
|
"ToastProgressIsNotBeingSynced": "Прогрес не синхронізується, перезапустіть відтворення",
|
||||||
|
"ToastProviderCreatedFailed": "Не вдалося додати постачальника",
|
||||||
|
"ToastProviderCreatedSuccess": "Новий постачальник доданий",
|
||||||
|
"ToastProviderNameAndUrlRequired": "Ім'я та URL обов'язкові",
|
||||||
|
"ToastProviderRemoveSuccess": "Постачальник видалений",
|
||||||
"ToastRSSFeedCloseFailed": "Не вдалося закрити RSS-канал",
|
"ToastRSSFeedCloseFailed": "Не вдалося закрити RSS-канал",
|
||||||
"ToastRSSFeedCloseSuccess": "RSS-канал закрито",
|
"ToastRSSFeedCloseSuccess": "RSS-канал закрито",
|
||||||
|
"ToastRemoveFailed": "Не вдалося видалити",
|
||||||
"ToastRemoveItemFromCollectionFailed": "Не вдалося видалити елемент із добірки",
|
"ToastRemoveItemFromCollectionFailed": "Не вдалося видалити елемент із добірки",
|
||||||
"ToastRemoveItemFromCollectionSuccess": "Елемент видалено з добірки",
|
"ToastRemoveItemFromCollectionSuccess": "Елемент видалено з добірки",
|
||||||
|
"ToastRemoveItemsWithIssuesFailed": "Не вдалося видалити елементи бібліотеки з проблемами",
|
||||||
|
"ToastRemoveItemsWithIssuesSuccess": "Видалено елементи бібліотеки з проблемами",
|
||||||
|
"ToastRenameFailed": "Не вдалося перейменувати",
|
||||||
|
"ToastRescanFailed": "Не вдалося повторно сканувати для {0}",
|
||||||
|
"ToastRescanRemoved": "Повторне сканування завершено, елемент був видалений",
|
||||||
|
"ToastRescanUpToDate": "Повторне сканування завершено, елемент актуальний",
|
||||||
|
"ToastRescanUpdated": "Повторне сканування завершено, елемент оновлено",
|
||||||
|
"ToastScanFailed": "Не вдалося сканувати елемент бібліотеки",
|
||||||
|
"ToastSelectAtLeastOneUser": "Виберіть хоча б одного користувача",
|
||||||
"ToastSendEbookToDeviceFailed": "Не вдалося надіслати електронну книгу на пристрій",
|
"ToastSendEbookToDeviceFailed": "Не вдалося надіслати електронну книгу на пристрій",
|
||||||
"ToastSendEbookToDeviceSuccess": "Електронну книгу надіслано на пристрій \"{0}\"",
|
"ToastSendEbookToDeviceSuccess": "Електронну книгу надіслано на пристрій \"{0}\"",
|
||||||
"ToastSeriesUpdateFailed": "Не вдалося оновити серію",
|
"ToastSeriesUpdateFailed": "Не вдалося оновити серію",
|
||||||
"ToastSeriesUpdateSuccess": "Серію успішно оновлено",
|
"ToastSeriesUpdateSuccess": "Серію успішно оновлено",
|
||||||
"ToastServerSettingsUpdateSuccess": "Налаштування сервера оновлено",
|
"ToastServerSettingsUpdateSuccess": "Налаштування сервера оновлено",
|
||||||
|
"ToastSessionCloseFailed": "Не вдалося закрити сесію",
|
||||||
"ToastSessionDeleteFailed": "Не вдалося видалити сесію",
|
"ToastSessionDeleteFailed": "Не вдалося видалити сесію",
|
||||||
"ToastSessionDeleteSuccess": "Сесію видалено",
|
"ToastSessionDeleteSuccess": "Сесію видалено",
|
||||||
|
"ToastSleepTimerDone": "Час сну завершено... зЗзЗз",
|
||||||
|
"ToastSlugMustChange": "Slug містить недопустимі символи",
|
||||||
|
"ToastSlugRequired": "Slug обов'язковий",
|
||||||
"ToastSocketConnected": "Сокет під'єднано",
|
"ToastSocketConnected": "Сокет під'єднано",
|
||||||
"ToastSocketDisconnected": "Сокет від'єднано",
|
"ToastSocketDisconnected": "Сокет від'єднано",
|
||||||
"ToastSocketFailedToConnect": "Не вдалося під'єднатися до сокета",
|
"ToastSocketFailedToConnect": "Не вдалося під'єднатися до сокета",
|
||||||
"ToastSortingPrefixesEmptyError": "Мусить мати хоча б 1 префікс сортування",
|
"ToastSortingPrefixesEmptyError": "Мусить мати хоча б 1 префікс сортування",
|
||||||
"ToastSortingPrefixesUpdateSuccess": "Префікси сортування оновлено ({0})",
|
"ToastSortingPrefixesUpdateSuccess": "Префікси сортування оновлено ({0})",
|
||||||
|
"ToastTitleRequired": "Заголовок обов'язковий",
|
||||||
|
"ToastUnknownError": "Невідома помилка",
|
||||||
|
"ToastUnlinkOpenIdFailed": "Не вдалося відв'язати користувача від OpenID",
|
||||||
|
"ToastUnlinkOpenIdSuccess": "Користувача відв'язано від OpenID",
|
||||||
"ToastUserDeleteFailed": "Не вдалося видалити користувача",
|
"ToastUserDeleteFailed": "Не вдалося видалити користувача",
|
||||||
"ToastUserDeleteSuccess": "Користувача видалено"
|
"ToastUserDeleteSuccess": "Користувача видалено",
|
||||||
|
"ToastUserPasswordChangeSuccess": "Пароль успішно змінено",
|
||||||
|
"ToastUserPasswordMismatch": "Паролі не збігаються",
|
||||||
|
"ToastUserPasswordMustChange": "Новий пароль не може співпадати з попереднім",
|
||||||
|
"ToastUserRootRequireName": "Потрібно ввести ім'я користувача root"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
"ButtonQuickMatch": "快速匹配",
|
"ButtonQuickMatch": "快速匹配",
|
||||||
"ButtonReScan": "重新扫描",
|
"ButtonReScan": "重新扫描",
|
||||||
"ButtonRead": "读取",
|
"ButtonRead": "读取",
|
||||||
"ButtonReadLess": "阅读更少",
|
"ButtonReadLess": "阅读较少",
|
||||||
"ButtonReadMore": "阅读更多",
|
"ButtonReadMore": "阅读更多",
|
||||||
"ButtonRefresh": "刷新",
|
"ButtonRefresh": "刷新",
|
||||||
"ButtonRemove": "移除",
|
"ButtonRemove": "移除",
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
"HeaderNotificationUpdate": "更新通知",
|
"HeaderNotificationUpdate": "更新通知",
|
||||||
"HeaderNotifications": "通知",
|
"HeaderNotifications": "通知",
|
||||||
"HeaderOpenIDConnectAuthentication": "OpenID 连接身份验证",
|
"HeaderOpenIDConnectAuthentication": "OpenID 连接身份验证",
|
||||||
|
"HeaderOpenListeningSessions": "打开收听会话",
|
||||||
"HeaderOpenRSSFeed": "打开 RSS 源",
|
"HeaderOpenRSSFeed": "打开 RSS 源",
|
||||||
"HeaderOtherFiles": "其他文件",
|
"HeaderOtherFiles": "其他文件",
|
||||||
"HeaderPasswordAuthentication": "密码认证",
|
"HeaderPasswordAuthentication": "密码认证",
|
||||||
@@ -219,13 +220,14 @@
|
|||||||
"LabelAddToPlaylist": "添加到播放列表",
|
"LabelAddToPlaylist": "添加到播放列表",
|
||||||
"LabelAddToPlaylistBatch": "添加 {0} 个项目到播放列表",
|
"LabelAddToPlaylistBatch": "添加 {0} 个项目到播放列表",
|
||||||
"LabelAddedAt": "添加于",
|
"LabelAddedAt": "添加于",
|
||||||
"LabelAddedDate": "添加 {0}",
|
"LabelAddedDate": "已添加 {0}",
|
||||||
"LabelAdminUsersOnly": "仅限管理员用户",
|
"LabelAdminUsersOnly": "仅限管理员用户",
|
||||||
"LabelAll": "全部",
|
"LabelAll": "全部",
|
||||||
"LabelAllUsers": "所有用户",
|
"LabelAllUsers": "所有用户",
|
||||||
"LabelAllUsersExcludingGuests": "除访客外的所有用户",
|
"LabelAllUsersExcludingGuests": "除访客外的所有用户",
|
||||||
"LabelAllUsersIncludingGuests": "包括访客的所有用户",
|
"LabelAllUsersIncludingGuests": "包括访客的所有用户",
|
||||||
"LabelAlreadyInYourLibrary": "已存在你的库中",
|
"LabelAlreadyInYourLibrary": "已存在你的库中",
|
||||||
|
"LabelApiToken": "API 令牌",
|
||||||
"LabelAppend": "附加",
|
"LabelAppend": "附加",
|
||||||
"LabelAudioBitrate": "音频比特率 (例如: 128k)",
|
"LabelAudioBitrate": "音频比特率 (例如: 128k)",
|
||||||
"LabelAudioChannels": "音频通道 (1 或 2)",
|
"LabelAudioChannels": "音频通道 (1 或 2)",
|
||||||
@@ -463,12 +465,14 @@
|
|||||||
"LabelOpenIDGroupClaimDescription": "OpenID 声明的名称, 该声明包含用户组的列表. 通常称为<code>组</code><b>如果已配置</b>, 应用程序将根据用户的组成员身份自动分配角色, 前提是这些组在声明中以不区分大小写的方式命名为 'Admin', 'User' 或 'Guest'. 声明应包含一个列表, 如果用户属于多个组, 则应用程序将分配与最高访问级别相对应的角色. 如果没有组匹配, 访问将被拒绝.",
|
"LabelOpenIDGroupClaimDescription": "OpenID 声明的名称, 该声明包含用户组的列表. 通常称为<code>组</code><b>如果已配置</b>, 应用程序将根据用户的组成员身份自动分配角色, 前提是这些组在声明中以不区分大小写的方式命名为 'Admin', 'User' 或 'Guest'. 声明应包含一个列表, 如果用户属于多个组, 则应用程序将分配与最高访问级别相对应的角色. 如果没有组匹配, 访问将被拒绝.",
|
||||||
"LabelOpenRSSFeed": "打开 RSS 源",
|
"LabelOpenRSSFeed": "打开 RSS 源",
|
||||||
"LabelOverwrite": "覆盖",
|
"LabelOverwrite": "覆盖",
|
||||||
|
"LabelPaginationPageXOfY": "第 {0} 页 共 {1} 页",
|
||||||
"LabelPassword": "密码",
|
"LabelPassword": "密码",
|
||||||
"LabelPath": "路径",
|
"LabelPath": "路径",
|
||||||
"LabelPermanent": "永久的",
|
"LabelPermanent": "永久的",
|
||||||
"LabelPermissionsAccessAllLibraries": "可以访问所有媒体库",
|
"LabelPermissionsAccessAllLibraries": "可以访问所有媒体库",
|
||||||
"LabelPermissionsAccessAllTags": "可以访问所有标签",
|
"LabelPermissionsAccessAllTags": "可以访问所有标签",
|
||||||
"LabelPermissionsAccessExplicitContent": "可以访问显式内容",
|
"LabelPermissionsAccessExplicitContent": "可以访问显式内容",
|
||||||
|
"LabelPermissionsCreateEreader": "可以创建电子阅读器",
|
||||||
"LabelPermissionsDelete": "可以删除",
|
"LabelPermissionsDelete": "可以删除",
|
||||||
"LabelPermissionsDownload": "可以下载",
|
"LabelPermissionsDownload": "可以下载",
|
||||||
"LabelPermissionsUpdate": "可以更新",
|
"LabelPermissionsUpdate": "可以更新",
|
||||||
@@ -559,6 +563,9 @@
|
|||||||
"LabelSettingsHideSingleBookSeriesHelp": "只有一本书的系列将从系列页面和主页书架中隐藏.",
|
"LabelSettingsHideSingleBookSeriesHelp": "只有一本书的系列将从系列页面和主页书架中隐藏.",
|
||||||
"LabelSettingsHomePageBookshelfView": "首页使用书架视图",
|
"LabelSettingsHomePageBookshelfView": "首页使用书架视图",
|
||||||
"LabelSettingsLibraryBookshelfView": "媒体库使用书架视图",
|
"LabelSettingsLibraryBookshelfView": "媒体库使用书架视图",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "完成百分比大于",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "剩余时间少于 (秒)",
|
||||||
|
"LabelSettingsLibraryMarkAsFinishedWhen": "当发生以下情况时将媒体项目标记为已完成",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "跳过继续系列中的早期书籍",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "跳过继续系列中的早期书籍",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "继续系列主页书架显示系列中未开始的第一本书, 该系列至少有一本书已完成且没有正在进行的书. 启用此设置将从最远完成的书开始系列, 而不是从第一本书开始.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "继续系列主页书架显示系列中未开始的第一本书, 该系列至少有一本书已完成且没有正在进行的书. 启用此设置将从最远完成的书开始系列, 而不是从第一本书开始.",
|
||||||
"LabelSettingsParseSubtitles": "解析副标题",
|
"LabelSettingsParseSubtitles": "解析副标题",
|
||||||
@@ -656,6 +663,7 @@
|
|||||||
"LabelUpdateDetailsHelp": "找到匹配项时允许覆盖所选书籍存在的详细信息",
|
"LabelUpdateDetailsHelp": "找到匹配项时允许覆盖所选书籍存在的详细信息",
|
||||||
"LabelUpdatedAt": "更新时间",
|
"LabelUpdatedAt": "更新时间",
|
||||||
"LabelUploaderDragAndDrop": "拖放文件或文件夹",
|
"LabelUploaderDragAndDrop": "拖放文件或文件夹",
|
||||||
|
"LabelUploaderDragAndDropFilesOnly": "拖放文件",
|
||||||
"LabelUploaderDropFiles": "删除文件",
|
"LabelUploaderDropFiles": "删除文件",
|
||||||
"LabelUploaderItemFetchMetadataHelp": "自动获取标题, 作者和系列",
|
"LabelUploaderItemFetchMetadataHelp": "自动获取标题, 作者和系列",
|
||||||
"LabelUseAdvancedOptions": "使用高级选项",
|
"LabelUseAdvancedOptions": "使用高级选项",
|
||||||
@@ -671,6 +679,8 @@
|
|||||||
"LabelViewPlayerSettings": "查看播放器设置",
|
"LabelViewPlayerSettings": "查看播放器设置",
|
||||||
"LabelViewQueue": "查看播放列表",
|
"LabelViewQueue": "查看播放列表",
|
||||||
"LabelVolume": "音量",
|
"LabelVolume": "音量",
|
||||||
|
"LabelWebRedirectURLsDescription": "在你的 OAuth 提供商中授权这些链接,以允许在登录后重定向回 Web 应用程序:",
|
||||||
|
"LabelWebRedirectURLsSubfolder": "重定向 URL 的子文件夹",
|
||||||
"LabelWeekdaysToRun": "工作日运行",
|
"LabelWeekdaysToRun": "工作日运行",
|
||||||
"LabelXBooks": "{0} 本书",
|
"LabelXBooks": "{0} 本书",
|
||||||
"LabelXItems": "{0} 项目",
|
"LabelXItems": "{0} 项目",
|
||||||
|
|||||||
+35
-19
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ButtonAdd": "增加",
|
"ButtonAdd": "添加",
|
||||||
"ButtonAddChapters": "新增章節",
|
"ButtonAddChapters": "新增章節",
|
||||||
"ButtonAddDevice": "新增設備",
|
"ButtonAddDevice": "新增設備",
|
||||||
"ButtonAddLibrary": "新增庫",
|
"ButtonAddLibrary": "新增庫",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"ButtonCheckAndDownloadNewEpisodes": "檢查並下載新劇集",
|
"ButtonCheckAndDownloadNewEpisodes": "檢查並下載新劇集",
|
||||||
"ButtonChooseAFolder": "選擇資料夾",
|
"ButtonChooseAFolder": "選擇資料夾",
|
||||||
"ButtonChooseFiles": "選擇檔案",
|
"ButtonChooseFiles": "選擇檔案",
|
||||||
"ButtonClearFilter": "清除過濾器",
|
"ButtonClearFilter": "清楚過濾器",
|
||||||
"ButtonCloseFeed": "關閉源",
|
"ButtonCloseFeed": "關閉源",
|
||||||
"ButtonCloseSession": "關閉開放會話",
|
"ButtonCloseSession": "關閉開放會話",
|
||||||
"ButtonCollections": "收藏",
|
"ButtonCollections": "收藏",
|
||||||
@@ -35,6 +35,8 @@
|
|||||||
"ButtonHide": "隱藏",
|
"ButtonHide": "隱藏",
|
||||||
"ButtonHome": "首頁",
|
"ButtonHome": "首頁",
|
||||||
"ButtonIssues": "問題",
|
"ButtonIssues": "問題",
|
||||||
|
"ButtonJumpBackward": "向後跳轉",
|
||||||
|
"ButtonJumpForward": "向前跳轉",
|
||||||
"ButtonLatest": "最新",
|
"ButtonLatest": "最新",
|
||||||
"ButtonLibrary": "媒體庫",
|
"ButtonLibrary": "媒體庫",
|
||||||
"ButtonLogout": "登出",
|
"ButtonLogout": "登出",
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
"ButtonPlay": "播放",
|
"ButtonPlay": "播放",
|
||||||
"ButtonPlaying": "正在播放",
|
"ButtonPlaying": "正在播放",
|
||||||
"ButtonPlaylists": "播放列表",
|
"ButtonPlaylists": "播放列表",
|
||||||
|
"ButtonPrevious": "上一個",
|
||||||
"ButtonPreviousChapter": "過去的章節",
|
"ButtonPreviousChapter": "過去的章節",
|
||||||
"ButtonPurgeAllCache": "清理所有快取",
|
"ButtonPurgeAllCache": "清理所有快取",
|
||||||
"ButtonPurgeItemsCache": "清理項目快取",
|
"ButtonPurgeItemsCache": "清理項目快取",
|
||||||
@@ -76,7 +79,7 @@
|
|||||||
"ButtonSaveTracklist": "保存音軌列表",
|
"ButtonSaveTracklist": "保存音軌列表",
|
||||||
"ButtonScan": "掃描",
|
"ButtonScan": "掃描",
|
||||||
"ButtonScanLibrary": "掃描庫",
|
"ButtonScanLibrary": "掃描庫",
|
||||||
"ButtonSearch": "查找",
|
"ButtonSearch": "搜索",
|
||||||
"ButtonSelectFolderPath": "選擇資料夾路徑",
|
"ButtonSelectFolderPath": "選擇資料夾路徑",
|
||||||
"ButtonSeries": "系列",
|
"ButtonSeries": "系列",
|
||||||
"ButtonSetChaptersFromTracks": "將音軌設定為章節",
|
"ButtonSetChaptersFromTracks": "將音軌設定為章節",
|
||||||
@@ -97,7 +100,7 @@
|
|||||||
"ErrorUploadFetchMetadataAPI": "獲取元數據時出錯",
|
"ErrorUploadFetchMetadataAPI": "獲取元數據時出錯",
|
||||||
"ErrorUploadFetchMetadataNoResults": "無法獲取元數據 - 嘗試更新標題和/或作者",
|
"ErrorUploadFetchMetadataNoResults": "無法獲取元數據 - 嘗試更新標題和/或作者",
|
||||||
"ErrorUploadLacksTitle": "必須有標題",
|
"ErrorUploadLacksTitle": "必須有標題",
|
||||||
"HeaderAccount": "帳號",
|
"HeaderAccount": "賬號",
|
||||||
"HeaderAdvanced": "高級",
|
"HeaderAdvanced": "高級",
|
||||||
"HeaderAppriseNotificationSettings": "測試通知設定",
|
"HeaderAppriseNotificationSettings": "測試通知設定",
|
||||||
"HeaderAudioTracks": "音軌",
|
"HeaderAudioTracks": "音軌",
|
||||||
@@ -111,6 +114,7 @@
|
|||||||
"HeaderCollectionItems": "收藏項目",
|
"HeaderCollectionItems": "收藏項目",
|
||||||
"HeaderCover": "封面",
|
"HeaderCover": "封面",
|
||||||
"HeaderCurrentDownloads": "當前下載",
|
"HeaderCurrentDownloads": "當前下載",
|
||||||
|
"HeaderCustomMessageOnLogin": "登錄時的自定義信息",
|
||||||
"HeaderCustomMetadataProviders": "自訂 Metadata 提供者",
|
"HeaderCustomMetadataProviders": "自訂 Metadata 提供者",
|
||||||
"HeaderDetails": "詳情",
|
"HeaderDetails": "詳情",
|
||||||
"HeaderDownloadQueue": "下載佇列",
|
"HeaderDownloadQueue": "下載佇列",
|
||||||
@@ -144,7 +148,7 @@
|
|||||||
"HeaderNewLibrary": "新建媒體庫",
|
"HeaderNewLibrary": "新建媒體庫",
|
||||||
"HeaderNotifications": "通知",
|
"HeaderNotifications": "通知",
|
||||||
"HeaderOpenIDConnectAuthentication": "OpenID 連接身份驗證",
|
"HeaderOpenIDConnectAuthentication": "OpenID 連接身份驗證",
|
||||||
"HeaderOpenRSSFeed": "打開 RSS 源",
|
"HeaderOpenRSSFeed": "打開 Rss 源",
|
||||||
"HeaderOtherFiles": "其他檔案",
|
"HeaderOtherFiles": "其他檔案",
|
||||||
"HeaderPasswordAuthentication": "密碼認證",
|
"HeaderPasswordAuthentication": "密碼認證",
|
||||||
"HeaderPermissions": "權限",
|
"HeaderPermissions": "權限",
|
||||||
@@ -168,7 +172,7 @@
|
|||||||
"HeaderSettingsExperimental": "實驗功能",
|
"HeaderSettingsExperimental": "實驗功能",
|
||||||
"HeaderSettingsGeneral": "通用",
|
"HeaderSettingsGeneral": "通用",
|
||||||
"HeaderSettingsScanner": "掃描",
|
"HeaderSettingsScanner": "掃描",
|
||||||
"HeaderSleepTimer": "睡眠計時",
|
"HeaderSleepTimer": "睡眠定時",
|
||||||
"HeaderStatsLargestItems": "最大的項目",
|
"HeaderStatsLargestItems": "最大的項目",
|
||||||
"HeaderStatsLongestItems": "項目時長(小時)",
|
"HeaderStatsLongestItems": "項目時長(小時)",
|
||||||
"HeaderStatsMinutesListeningChart": "收聽分鐘數(最近7天)",
|
"HeaderStatsMinutesListeningChart": "收聽分鐘數(最近7天)",
|
||||||
@@ -182,8 +186,12 @@
|
|||||||
"HeaderUpdateDetails": "更新詳情",
|
"HeaderUpdateDetails": "更新詳情",
|
||||||
"HeaderUpdateLibrary": "更新媒體庫",
|
"HeaderUpdateLibrary": "更新媒體庫",
|
||||||
"HeaderUsers": "使用者",
|
"HeaderUsers": "使用者",
|
||||||
|
"HeaderYearReview": "{0} 年回顧",
|
||||||
"HeaderYourStats": "你的統計數據",
|
"HeaderYourStats": "你的統計數據",
|
||||||
"LabelAbridged": "概要",
|
"LabelAbridged": "概要",
|
||||||
|
"LabelAbridgedChecked": "刪節版(已勾選)",
|
||||||
|
"LabelAbridgedUnchecked": "未刪節版(未勾選)",
|
||||||
|
"LabelAccessibleBy": "可訪問",
|
||||||
"LabelAccountType": "帳號類型",
|
"LabelAccountType": "帳號類型",
|
||||||
"LabelAccountTypeAdmin": "管理員",
|
"LabelAccountTypeAdmin": "管理員",
|
||||||
"LabelAccountTypeGuest": "來賓",
|
"LabelAccountTypeGuest": "來賓",
|
||||||
@@ -260,26 +268,32 @@
|
|||||||
"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": "停用 SSL 證書驗證可能會使您的連接暴露於安全風險中,例如中間人攻擊。僅在您了解其含義並信任您所連接的郵件伺服器的情況下才停用此選項。",
|
||||||
"LabelEmailSettingsSecure": "安全",
|
"LabelEmailSettingsSecure": "安全",
|
||||||
"LabelEmailSettingsSecureHelp": "如果選是, 則連接將在連接到伺服器時使用TLS. 如果選否, 則若伺服器支援STARTTLS擴展, 則使用TLS. 在大多數情況下, 如果連接到465埠, 請將該值設定為是. 對於587或25埠, 請保持為否. (來自nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "如果選是, 則連接將在連接到伺服器時使用TLS. 如果選否, 則若伺服器支援STARTTLS擴展, 則使用TLS. 在大多數情況下, 如果連接到465埠, 請將該值設定為是. 對於587或25埠, 請保持為否. (來自nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "測試位址",
|
"LabelEmailSettingsTestAddress": "測試位址",
|
||||||
"LabelEmbeddedCover": "嵌入封面",
|
"LabelEmbeddedCover": "嵌入封面",
|
||||||
"LabelEnable": "啟用",
|
"LabelEnable": "啟用",
|
||||||
"LabelEnd": "結束",
|
"LabelEnd": "結束",
|
||||||
|
"LabelEndOfChapter": "章節結束",
|
||||||
"LabelEpisode": "劇集",
|
"LabelEpisode": "劇集",
|
||||||
"LabelEpisodeTitle": "劇集標題",
|
"LabelEpisodeTitle": "劇集標題",
|
||||||
"LabelEpisodeType": "劇集類型",
|
"LabelEpisodeType": "劇集類型",
|
||||||
"LabelExample": "示例",
|
"LabelExample": "示例",
|
||||||
"LabelExplicit": "信息準確",
|
"LabelExplicit": "信息準確",
|
||||||
"LabelFeedURL": "源 URL",
|
"LabelFeedURL": "源鏈接",
|
||||||
"LabelFetchingMetadata": "正在獲取元數據",
|
"LabelFetchingMetadata": "正在獲取元數據",
|
||||||
"LabelFile": "檔案",
|
"LabelFile": "文件",
|
||||||
"LabelFileBirthtime": "檔案創建時間",
|
"LabelFileBirthtime": "檔案創建時間",
|
||||||
"LabelFileModified": "檔案修改時間",
|
"LabelFileModified": "檔案修改時間",
|
||||||
"LabelFilename": "檔名",
|
"LabelFilename": "檔名",
|
||||||
@@ -288,6 +302,7 @@
|
|||||||
"LabelFinished": "已聽完",
|
"LabelFinished": "已聽完",
|
||||||
"LabelFolder": "資料夾",
|
"LabelFolder": "資料夾",
|
||||||
"LabelFolders": "資料夾",
|
"LabelFolders": "資料夾",
|
||||||
|
"LabelFontBoldness": "字體粗細",
|
||||||
"LabelFontFamily": "字體系列",
|
"LabelFontFamily": "字體系列",
|
||||||
"LabelFontItalic": "斜體",
|
"LabelFontItalic": "斜體",
|
||||||
"LabelFontScale": "字體比例",
|
"LabelFontScale": "字體比例",
|
||||||
@@ -353,7 +368,7 @@
|
|||||||
"LabelMobileRedirectURIs": "允許移動應用重定向 URI",
|
"LabelMobileRedirectURIs": "允許移動應用重定向 URI",
|
||||||
"LabelMobileRedirectURIsDescription": "這是移動應用程序的有效重定向 URI 白名單. 預設值為 <code>audiobookshelf://oauth</code>,您可以刪除它或加入其他 URI 以進行第三方應用集成. 使用星號 (<code>*</code>) 作為唯一條目允許任何 URI.",
|
"LabelMobileRedirectURIsDescription": "這是移動應用程序的有效重定向 URI 白名單. 預設值為 <code>audiobookshelf://oauth</code>,您可以刪除它或加入其他 URI 以進行第三方應用集成. 使用星號 (<code>*</code>) 作為唯一條目允許任何 URI.",
|
||||||
"LabelMore": "更多",
|
"LabelMore": "更多",
|
||||||
"LabelMoreInfo": "更多..",
|
"LabelMoreInfo": "更多信息",
|
||||||
"LabelName": "名稱",
|
"LabelName": "名稱",
|
||||||
"LabelNarrator": "講述者",
|
"LabelNarrator": "講述者",
|
||||||
"LabelNarrators": "講述者",
|
"LabelNarrators": "講述者",
|
||||||
@@ -399,7 +414,7 @@
|
|||||||
"LabelPodcasts": "播客",
|
"LabelPodcasts": "播客",
|
||||||
"LabelPort": "埠",
|
"LabelPort": "埠",
|
||||||
"LabelPrefixesToIgnore": "忽略的前綴 (不區分大小寫)",
|
"LabelPrefixesToIgnore": "忽略的前綴 (不區分大小寫)",
|
||||||
"LabelPreventIndexing": "防止 iTunes 和 Google 播客目錄對你的源進行索引",
|
"LabelPreventIndexing": "防止您的訂閱源被 iTunes 和 Google 播客目錄索引",
|
||||||
"LabelPrimaryEbook": "主電子書",
|
"LabelPrimaryEbook": "主電子書",
|
||||||
"LabelProgress": "進度",
|
"LabelProgress": "進度",
|
||||||
"LabelProvider": "供應商",
|
"LabelProvider": "供應商",
|
||||||
@@ -412,6 +427,7 @@
|
|||||||
"LabelRSSFeedPreventIndexing": "防止索引",
|
"LabelRSSFeedPreventIndexing": "防止索引",
|
||||||
"LabelRSSFeedSlug": "RSS 源段",
|
"LabelRSSFeedSlug": "RSS 源段",
|
||||||
"LabelRSSFeedURL": "RSS 源 URL",
|
"LabelRSSFeedURL": "RSS 源 URL",
|
||||||
|
"LabelRandomly": "隨機",
|
||||||
"LabelRead": "閱讀",
|
"LabelRead": "閱讀",
|
||||||
"LabelReadAgain": "再次閱讀",
|
"LabelReadAgain": "再次閱讀",
|
||||||
"LabelReadEbookWithoutProgress": "閱讀電子書而不保存進度",
|
"LabelReadEbookWithoutProgress": "閱讀電子書而不保存進度",
|
||||||
@@ -635,20 +651,20 @@
|
|||||||
"MessageNoFoldersAvailable": "沒有可用資料夾",
|
"MessageNoFoldersAvailable": "沒有可用資料夾",
|
||||||
"MessageNoGenres": "無流派",
|
"MessageNoGenres": "無流派",
|
||||||
"MessageNoIssues": "無問題",
|
"MessageNoIssues": "無問題",
|
||||||
"MessageNoItems": "無項目",
|
"MessageNoItems": "沒有項目",
|
||||||
"MessageNoItemsFound": "未找到任何項目",
|
"MessageNoItemsFound": "沒有找到任何項目",
|
||||||
"MessageNoListeningSessions": "無收聽會話",
|
"MessageNoListeningSessions": "沒有收聽會話",
|
||||||
"MessageNoLogs": "無日誌",
|
"MessageNoLogs": "無日誌",
|
||||||
"MessageNoMediaProgress": "無媒體進度",
|
"MessageNoMediaProgress": "無媒體進度",
|
||||||
"MessageNoNotifications": "無通知",
|
"MessageNoNotifications": "無通知",
|
||||||
"MessageNoPodcastsFound": "未找到播客",
|
"MessageNoPodcastsFound": "沒有找到播客",
|
||||||
"MessageNoResults": "無結果",
|
"MessageNoResults": "無結果",
|
||||||
"MessageNoSearchResultsFor": "沒有搜尋到結果 \"{0}\"",
|
"MessageNoSearchResultsFor": "沒有搜尋到結果 \"{0}\"",
|
||||||
"MessageNoSeries": "無系列",
|
"MessageNoSeries": "無系列",
|
||||||
"MessageNoTags": "無標籤",
|
"MessageNoTags": "無標籤",
|
||||||
"MessageNoTasksRunning": "沒有正在運行的任務",
|
"MessageNoTasksRunning": "沒有正在運行的任務",
|
||||||
"MessageNoUpdatesWereNecessary": "無需更新",
|
"MessageNoUpdatesWereNecessary": "無需更新",
|
||||||
"MessageNoUserPlaylists": "你沒有播放列表",
|
"MessageNoUserPlaylists": "您沒有播放列表",
|
||||||
"MessageNotYetImplemented": "尚未實施",
|
"MessageNotYetImplemented": "尚未實施",
|
||||||
"MessageOr": "或",
|
"MessageOr": "或",
|
||||||
"MessagePauseChapter": "暫停章節播放",
|
"MessagePauseChapter": "暫停章節播放",
|
||||||
@@ -660,7 +676,7 @@
|
|||||||
"MessageRemoveEpisodes": "移除 {0} 劇集",
|
"MessageRemoveEpisodes": "移除 {0} 劇集",
|
||||||
"MessageRemoveFromPlayerQueue": "從播放佇列中移除",
|
"MessageRemoveFromPlayerQueue": "從播放佇列中移除",
|
||||||
"MessageRemoveUserWarning": "是否確實要永久刪除使用者 \"{0}\"?",
|
"MessageRemoveUserWarning": "是否確實要永久刪除使用者 \"{0}\"?",
|
||||||
"MessageReportBugsAndContribute": "報告錯誤、請求功能和貢獻在",
|
"MessageReportBugsAndContribute": "報告錯誤、請求功能和做出貢獻",
|
||||||
"MessageResetChaptersConfirm": "你確定要重置章節並撤消你所做的更改嗎?",
|
"MessageResetChaptersConfirm": "你確定要重置章節並撤消你所做的更改嗎?",
|
||||||
"MessageRestoreBackupConfirm": "你確定要恢復創建的這個備份",
|
"MessageRestoreBackupConfirm": "你確定要恢復創建的這個備份",
|
||||||
"MessageRestoreBackupWarning": "恢復備份將覆蓋位於 /config 的整個資料庫並覆蓋 /metadata/items & /metadata/authors 中的圖像.<br /><br />備份不會修改媒體庫資料夾中的任何檔案. 如果您已啟用伺服器設定將封面和元數據存儲在庫資料夾中,則不會備份或覆蓋這些內容.<br /><br />將自動刷新使用伺服器的所有客戶端.",
|
"MessageRestoreBackupWarning": "恢復備份將覆蓋位於 /config 的整個資料庫並覆蓋 /metadata/items & /metadata/authors 中的圖像.<br /><br />備份不會修改媒體庫資料夾中的任何檔案. 如果您已啟用伺服器設定將封面和元數據存儲在庫資料夾中,則不會備份或覆蓋這些內容.<br /><br />將自動刷新使用伺服器的所有客戶端.",
|
||||||
@@ -681,8 +697,8 @@
|
|||||||
"NoteChangeRootPassword": "Root 是唯一可以擁有空密碼的使用者",
|
"NoteChangeRootPassword": "Root 是唯一可以擁有空密碼的使用者",
|
||||||
"NoteChapterEditorTimes": "注意: 第一章開始時間必須保持在 0:00, 最後一章開始時間不能超過有聲書持續時間.",
|
"NoteChapterEditorTimes": "注意: 第一章開始時間必須保持在 0:00, 最後一章開始時間不能超過有聲書持續時間.",
|
||||||
"NoteFolderPicker": "注意: 將不顯示已映射的資料夾",
|
"NoteFolderPicker": "注意: 將不顯示已映射的資料夾",
|
||||||
"NoteRSSFeedPodcastAppsHttps": "警告: 大多數播客應用程序都需要 RSS 源 URL 使用 HTTPS",
|
"NoteRSSFeedPodcastAppsHttps": "警告:大多數播客應用程式要求 RSS 訂閱源 URL 使用 HTTPS",
|
||||||
"NoteRSSFeedPodcastAppsPubDate": "警告: 您的一集或多集沒有發布日期. 一些播客應用程序要求這樣做.",
|
"NoteRSSFeedPodcastAppsPubDate": "警告:您的一個或多個劇集沒有發布日期。某些播客應用程式要求提供此資訊。",
|
||||||
"NoteUploaderFoldersWithMediaFiles": "包含媒體檔案的資料夾將作為單獨的媒體庫項目處理.",
|
"NoteUploaderFoldersWithMediaFiles": "包含媒體檔案的資料夾將作為單獨的媒體庫項目處理.",
|
||||||
"NoteUploaderOnlyAudioFiles": "如果只上傳音頻檔, 則每個音頻檔將作為單獨的有聲書處理.",
|
"NoteUploaderOnlyAudioFiles": "如果只上傳音頻檔, 則每個音頻檔將作為單獨的有聲書處理.",
|
||||||
"NoteUploaderUnsupportedFiles": "不支援的檔案將被忽略. 選擇或刪除資料夾時, 將忽略不在項目資料夾中的其他檔案.",
|
"NoteUploaderUnsupportedFiles": "不支援的檔案將被忽略. 選擇或刪除資料夾時, 將忽略不在項目資料夾中的其他檔案.",
|
||||||
@@ -705,7 +721,7 @@
|
|||||||
"ToastBackupUploadSuccess": "備份已上傳",
|
"ToastBackupUploadSuccess": "備份已上傳",
|
||||||
"ToastBatchUpdateFailed": "批量更新失敗",
|
"ToastBatchUpdateFailed": "批量更新失敗",
|
||||||
"ToastBatchUpdateSuccess": "批量更新成功",
|
"ToastBatchUpdateSuccess": "批量更新成功",
|
||||||
"ToastBookmarkCreateFailed": "創建書籤失敗",
|
"ToastBookmarkCreateFailed": "創建書簽失敗",
|
||||||
"ToastBookmarkCreateSuccess": "書籤已新增",
|
"ToastBookmarkCreateSuccess": "書籤已新增",
|
||||||
"ToastBookmarkRemoveSuccess": "書籤已刪除",
|
"ToastBookmarkRemoveSuccess": "書籤已刪除",
|
||||||
"ToastBookmarkUpdateSuccess": "書籤已更新",
|
"ToastBookmarkUpdateSuccess": "書籤已更新",
|
||||||
|
|||||||
+2
-5
@@ -1,6 +1,4 @@
|
|||||||
### EXAMPLE DOCKER COMPOSE ###
|
### EXAMPLE DOCKER COMPOSE ###
|
||||||
version: "3.7"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
audiobookshelf:
|
audiobookshelf:
|
||||||
image: ghcr.io/advplyr/audiobookshelf:latest
|
image: ghcr.io/advplyr/audiobookshelf:latest
|
||||||
@@ -23,8 +21,7 @@ services:
|
|||||||
# you are running ABS on
|
# you are running ABS on
|
||||||
- ./config:/config
|
- ./config:/config
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# You can use the following environment variable to run the ABS
|
# You can use the following user directive to run the ABS
|
||||||
# docker container as a specific user. You will need to change
|
# docker container as a specific user. You will need to change
|
||||||
# the UID and GID to the correct values for your user.
|
# the UID and GID to the correct values for your user.
|
||||||
#environment:
|
# user: 1000:1000
|
||||||
# - user=1000:1000
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ if (isDev) {
|
|||||||
if (devEnv.FFProbePath) process.env.FFPROBE_PATH = devEnv.FFProbePath
|
if (devEnv.FFProbePath) process.env.FFPROBE_PATH = devEnv.FFProbePath
|
||||||
if (devEnv.NunicodePath) process.env.NUSQLITE3_PATH = devEnv.NunicodePath
|
if (devEnv.NunicodePath) process.env.NUSQLITE3_PATH = devEnv.NunicodePath
|
||||||
if (devEnv.SkipBinariesCheck) process.env.SKIP_BINARIES_CHECK = '1'
|
if (devEnv.SkipBinariesCheck) process.env.SKIP_BINARIES_CHECK = '1'
|
||||||
|
if (devEnv.AllowIframe) process.env.ALLOW_IFRAME = '1'
|
||||||
if (devEnv.BackupPath) process.env.BACKUP_PATH = devEnv.BackupPath
|
if (devEnv.BackupPath) process.env.BACKUP_PATH = devEnv.BackupPath
|
||||||
process.env.SOURCE = 'local'
|
process.env.SOURCE = 'local'
|
||||||
process.env.ROUTER_BASE_PATH = devEnv.RouterBasePath || ''
|
process.env.ROUTER_BASE_PATH = devEnv.RouterBasePath || ''
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.15.1",
|
"version": "2.17.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.15.1",
|
"version": "2.17.5",
|
||||||
"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.15.1",
|
"version": "2.17.5",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast server",
|
"description": "Self-hosted audiobook and podcast server",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ Is there a feature you are looking for? [Suggest it](https://github.com/advplyr/
|
|||||||
|
|
||||||
Join us on [Discord](https://discord.gg/HQgCbd6E75)
|
Join us on [Discord](https://discord.gg/HQgCbd6E75)
|
||||||
|
|
||||||
|
### Demo
|
||||||
|
|
||||||
|
Check out the web client demo: https://audiobooks.dev/ (thanks for hosting [@Vito0912](https://github.com/Vito0912)!)
|
||||||
|
|
||||||
|
Username/password: `demo`/`demo` (user account)
|
||||||
|
|
||||||
|
|
||||||
### Android App (beta)
|
### Android App (beta)
|
||||||
|
|
||||||
Try it out on the [Google Play Store](https://play.google.com/store/apps/details?id=com.audiobookshelf.app)
|
Try it out on the [Google Play Store](https://play.google.com/store/apps/details?id=com.audiobookshelf.app)
|
||||||
@@ -114,7 +121,7 @@ server {
|
|||||||
proxy_pass http://<URL_to_forward_to>;
|
proxy_pass http://<URL_to_forward_to>;
|
||||||
proxy_redirect http:// https://;
|
proxy_redirect http:// https://;
|
||||||
|
|
||||||
# Prevent 413 Request Entity Too Large error
|
# Prevent 413 Request Entity Too Large error
|
||||||
# by increasing the maximum allowed size of the client request body
|
# by increasing the maximum allowed size of the client request body
|
||||||
# For example, set it to 10 GiB
|
# For example, set it to 10 GiB
|
||||||
client_max_body_size 10240M;
|
client_max_body_size 10240M;
|
||||||
@@ -339,7 +346,7 @@ This application is built using [NodeJs](https://nodejs.org/).
|
|||||||
|
|
||||||
### Localization
|
### Localization
|
||||||
|
|
||||||
Thank you to [Weblate](https://hosted.weblate.org/engage/audiobookshelf/) for hosting our localization infrastructure pro-bono. If you want to see Audiobookshelf in your language, please help us localize. Additional information on helping with the translations [here](https://www.audiobookshelf.org/faq#how-do-i-help-with-translations). <a href="https://hosted.weblate.org/engage/audiobookshelf/"> <img src="https://hosted.weblate.org/widget/audiobookshelf/horizontal-auto.svg" alt="Translation status" /> </a>
|
Thank you to [Weblate](https://hosted.weblate.org/engage/audiobookshelf/) for hosting our localization infrastructure pro-bono. If you want to see Audiobookshelf in your language, please help us localize. Additional information on helping with the translations [here](https://www.audiobookshelf.org/faq#how-do-i-help-with-translations). <a href="https://hosted.weblate.org/engage/audiobookshelf/"> <img src="https://hosted.weblate.org/widget/audiobookshelf/abs-web-client/horizontal-auto.svg" alt="Translation status" /> </a>
|
||||||
|
|
||||||
### Dev Container Setup
|
### Dev Container Setup
|
||||||
|
|
||||||
|
|||||||
+34
-24
@@ -18,6 +18,26 @@ class Auth {
|
|||||||
constructor() {
|
constructor() {
|
||||||
// Map of openId sessions indexed by oauth2 state-variable
|
// Map of openId sessions indexed by oauth2 state-variable
|
||||||
this.openIdAuthSession = new Map()
|
this.openIdAuthSession = new Map()
|
||||||
|
this.ignorePatterns = [/\/api\/items\/[^/]+\/cover/, /\/api\/authors\/[^/]+\/image/]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the request should not be authenticated.
|
||||||
|
* @param {Request} req
|
||||||
|
* @returns {boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
authNotNeeded(req) {
|
||||||
|
return req.method === 'GET' && this.ignorePatterns.some((pattern) => pattern.test(req.originalUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
ifAuthNeeded(middleware) {
|
||||||
|
return (req, res, next) => {
|
||||||
|
if (this.authNotNeeded(req)) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
middleware(req, res, next)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,7 +131,7 @@ class Auth {
|
|||||||
{
|
{
|
||||||
client: openIdClient,
|
client: openIdClient,
|
||||||
params: {
|
params: {
|
||||||
redirect_uri: '/auth/openid/callback',
|
redirect_uri: `${global.ServerSettings.authOpenIDSubfolderForRedirectURLs}/auth/openid/callback`,
|
||||||
scope: 'openid profile email'
|
scope: 'openid profile email'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -460,9 +480,9 @@ class Auth {
|
|||||||
// for the request to mobile-redirect and as such the session is not shared
|
// for the request to mobile-redirect and as such the session is not shared
|
||||||
this.openIdAuthSession.set(state, { mobile_redirect_uri: req.query.redirect_uri })
|
this.openIdAuthSession.set(state, { mobile_redirect_uri: req.query.redirect_uri })
|
||||||
|
|
||||||
redirectUri = new URL('/auth/openid/mobile-redirect', hostUrl).toString()
|
redirectUri = new URL(`${global.ServerSettings.authOpenIDSubfolderForRedirectURLs}/auth/openid/mobile-redirect`, hostUrl).toString()
|
||||||
} else {
|
} else {
|
||||||
redirectUri = new URL('/auth/openid/callback', hostUrl).toString()
|
redirectUri = new URL(`${global.ServerSettings.authOpenIDSubfolderForRedirectURLs}/auth/openid/callback`, hostUrl).toString()
|
||||||
|
|
||||||
if (req.query.state) {
|
if (req.query.state) {
|
||||||
Logger.debug(`[Auth] Invalid state - not allowed on web openid flow`)
|
Logger.debug(`[Auth] Invalid state - not allowed on web openid flow`)
|
||||||
@@ -713,7 +733,7 @@ class Auth {
|
|||||||
const host = req.get('host')
|
const host = req.get('host')
|
||||||
// TODO: ABS does currently not support subfolders for installation
|
// TODO: ABS does currently not support subfolders for installation
|
||||||
// If we want to support it we need to include a config for the serverurl
|
// If we want to support it we need to include a config for the serverurl
|
||||||
postLogoutRedirectUri = `${protocol}://${host}/login`
|
postLogoutRedirectUri = `${protocol}://${host}${global.RouterBasePath}/login`
|
||||||
}
|
}
|
||||||
// else for openid-mobile we keep postLogoutRedirectUri on null
|
// else for openid-mobile we keep postLogoutRedirectUri on null
|
||||||
// nice would be to redirect to the app here, but for example Authentik does not implement
|
// nice would be to redirect to the app here, but for example Authentik does not implement
|
||||||
@@ -970,28 +990,18 @@ class Auth {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
Database.userModel
|
await matchingUser.update({ pash: pw })
|
||||||
.update(
|
Logger.info(`[Auth] User "${matchingUser.username}" changed password`)
|
||||||
{
|
res.json({
|
||||||
pash: pw
|
success: true
|
||||||
},
|
|
||||||
{
|
|
||||||
where: { id: matchingUser.id }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
Logger.info(`[Auth] User "${matchingUser.username}" changed password`)
|
|
||||||
res.json({
|
|
||||||
success: true
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
} catch (error) {
|
||||||
Logger.error(`[Auth] User "${matchingUser.username}" failed to change password`, error)
|
Logger.error(`[Auth] User "${matchingUser.username}" failed to change password`, error)
|
||||||
res.json({
|
res.json({
|
||||||
error: 'Unknown error'
|
error: 'Unknown error'
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -406,11 +406,6 @@ class Database {
|
|||||||
return Promise.all(oldBooks.map((oldBook) => this.models.book.saveFromOld(oldBook)))
|
return Promise.all(oldBooks.map((oldBook) => this.models.book.saveFromOld(oldBook)))
|
||||||
}
|
}
|
||||||
|
|
||||||
removeLibrary(libraryId) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
return this.models.library.removeById(libraryId)
|
|
||||||
}
|
|
||||||
|
|
||||||
createBulkCollectionBooks(collectionBooks) {
|
createBulkCollectionBooks(collectionBooks) {
|
||||||
if (!this.sequelize) return false
|
if (!this.sequelize) return false
|
||||||
return this.models.collectionBook.bulkCreate(collectionBooks)
|
return this.models.collectionBook.bulkCreate(collectionBooks)
|
||||||
@@ -449,21 +444,6 @@ class Database {
|
|||||||
return updated
|
return updated
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFeed(oldFeed) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
await this.models.feed.fullCreateFromOld(oldFeed)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFeed(oldFeed) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
return this.models.feed.fullUpdateFromOld(oldFeed)
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeFeed(feedId) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
await this.models.feed.removeById(feedId)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
+50
-49
@@ -62,7 +62,6 @@ class Server {
|
|||||||
fs.mkdirSync(global.MetadataPath)
|
fs.mkdirSync(global.MetadataPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.watcher = new Watcher()
|
|
||||||
this.auth = new Auth()
|
this.auth = new Auth()
|
||||||
|
|
||||||
// Managers
|
// Managers
|
||||||
@@ -70,9 +69,8 @@ class Server {
|
|||||||
this.backupManager = new BackupManager()
|
this.backupManager = new BackupManager()
|
||||||
this.abMergeManager = new AbMergeManager()
|
this.abMergeManager = new AbMergeManager()
|
||||||
this.playbackSessionManager = new PlaybackSessionManager()
|
this.playbackSessionManager = new PlaybackSessionManager()
|
||||||
this.podcastManager = new PodcastManager(this.watcher)
|
this.podcastManager = new PodcastManager()
|
||||||
this.audioMetadataManager = new AudioMetadataMangaer()
|
this.audioMetadataManager = new AudioMetadataMangaer()
|
||||||
this.rssFeedManager = new RssFeedManager()
|
|
||||||
this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager)
|
this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager)
|
||||||
this.apiCacheManager = new ApiCacheManager()
|
this.apiCacheManager = new ApiCacheManager()
|
||||||
this.binaryManager = new BinaryManager()
|
this.binaryManager = new BinaryManager()
|
||||||
@@ -85,7 +83,6 @@ class Server {
|
|||||||
Logger.logManager = new LogManager()
|
Logger.logManager = new LogManager()
|
||||||
|
|
||||||
this.server = null
|
this.server = null
|
||||||
this.io = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,7 +136,7 @@ class Server {
|
|||||||
|
|
||||||
await ShareManager.init()
|
await ShareManager.init()
|
||||||
await this.backupManager.init()
|
await this.backupManager.init()
|
||||||
await this.rssFeedManager.init()
|
await RssFeedManager.init()
|
||||||
|
|
||||||
const libraries = await Database.libraryModel.getAllWithFolders()
|
const libraries = await Database.libraryModel.getAllWithFolders()
|
||||||
await this.cronManager.init(libraries)
|
await this.cronManager.init(libraries)
|
||||||
@@ -147,9 +144,12 @@ class Server {
|
|||||||
|
|
||||||
if (Database.serverSettings.scannerDisableWatcher) {
|
if (Database.serverSettings.scannerDisableWatcher) {
|
||||||
Logger.info(`[Server] Watcher is disabled`)
|
Logger.info(`[Server] Watcher is disabled`)
|
||||||
this.watcher.disabled = true
|
Watcher.disabled = true
|
||||||
} else {
|
} else {
|
||||||
this.watcher.initWatcher(libraries)
|
Watcher.initWatcher(libraries)
|
||||||
|
Watcher.on('scanFilesChanged', (pendingFileUpdates, pendingTask) => {
|
||||||
|
LibraryScanner.scanFilesChanged(pendingFileUpdates, pendingTask)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,18 +192,23 @@ class Server {
|
|||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
/**
|
|
||||||
* @temporary
|
|
||||||
* This is necessary for the ebook & cover API endpoint in the mobile apps
|
|
||||||
* The mobile app ereader is using fetch api in Capacitor that is currently difficult to switch to native requests
|
|
||||||
* so we have to allow cors for specific origins to the /api/items/:id/ebook endpoint
|
|
||||||
* The cover image is fetched with XMLHttpRequest in the mobile apps to load into a canvas and extract colors
|
|
||||||
* @see https://ionicframework.com/docs/troubleshooting/cors
|
|
||||||
*
|
|
||||||
* Running in development allows cors to allow testing the mobile apps in the browser
|
|
||||||
* or env variable ALLOW_CORS = '1'
|
|
||||||
*/
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
|
if (!global.ServerSettings.allowIframe) {
|
||||||
|
// Prevent clickjacking by disallowing iframes
|
||||||
|
res.setHeader('Content-Security-Policy', "frame-ancestors 'self'")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @temporary
|
||||||
|
* This is necessary for the ebook & cover API endpoint in the mobile apps
|
||||||
|
* The mobile app ereader is using fetch api in Capacitor that is currently difficult to switch to native requests
|
||||||
|
* so we have to allow cors for specific origins to the /api/items/:id/ebook endpoint
|
||||||
|
* The cover image is fetched with XMLHttpRequest in the mobile apps to load into a canvas and extract colors
|
||||||
|
* @see https://ionicframework.com/docs/troubleshooting/cors
|
||||||
|
*
|
||||||
|
* Running in development allows cors to allow testing the mobile apps in the browser
|
||||||
|
* or env variable ALLOW_CORS = '1'
|
||||||
|
*/
|
||||||
if (Logger.isDev || req.path.match(/\/api\/items\/([a-z0-9-]{36})\/(ebook|cover)(\/[0-9]+)?/)) {
|
if (Logger.isDev || req.path.match(/\/api\/items\/([a-z0-9-]{36})\/(ebook|cover)(\/[0-9]+)?/)) {
|
||||||
const allowedOrigins = ['capacitor://localhost', 'http://localhost']
|
const allowedOrigins = ['capacitor://localhost', 'http://localhost']
|
||||||
if (global.AllowCors || Logger.isDev || allowedOrigins.some((o) => o === req.get('origin'))) {
|
if (global.AllowCors || Logger.isDev || allowedOrigins.some((o) => o === req.get('origin'))) {
|
||||||
@@ -238,20 +243,23 @@ class Server {
|
|||||||
// init passport.js
|
// init passport.js
|
||||||
app.use(passport.initialize())
|
app.use(passport.initialize())
|
||||||
// register passport in express-session
|
// register passport in express-session
|
||||||
app.use(passport.session())
|
app.use(this.auth.ifAuthNeeded(passport.session()))
|
||||||
// config passport.js
|
// config passport.js
|
||||||
await this.auth.initPassportJs()
|
await this.auth.initPassportJs()
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
// if RouterBasePath is set, modify all requests to include the base path
|
// if RouterBasePath is set, modify all requests to include the base path
|
||||||
if (global.RouterBasePath) {
|
app.use((req, res, next) => {
|
||||||
app.use((req, res, next) => {
|
const urlStartsWithRouterBasePath = req.url.startsWith(global.RouterBasePath)
|
||||||
if (!req.url.startsWith(global.RouterBasePath)) {
|
const host = req.get('host')
|
||||||
req.url = `${global.RouterBasePath}${req.url}`
|
const protocol = req.secure || req.get('x-forwarded-proto') === 'https' ? 'https' : 'http'
|
||||||
}
|
const prefix = urlStartsWithRouterBasePath ? global.RouterBasePath : ''
|
||||||
next()
|
req.originalHostPrefix = `${protocol}://${host}${prefix}`
|
||||||
})
|
if (!urlStartsWithRouterBasePath) {
|
||||||
}
|
req.url = `${global.RouterBasePath}${req.url}`
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
})
|
||||||
app.use(global.RouterBasePath, router)
|
app.use(global.RouterBasePath, router)
|
||||||
app.disable('x-powered-by')
|
app.disable('x-powered-by')
|
||||||
|
|
||||||
@@ -268,6 +276,10 @@ class Server {
|
|||||||
router.use(express.urlencoded({ extended: true, limit: '5mb' }))
|
router.use(express.urlencoded({ extended: true, limit: '5mb' }))
|
||||||
router.use(express.json({ limit: '5mb' }))
|
router.use(express.json({ limit: '5mb' }))
|
||||||
|
|
||||||
|
router.use('/api', this.auth.ifAuthNeeded(this.authMiddleware.bind(this)), this.apiRouter.router)
|
||||||
|
router.use('/hls', this.authMiddleware.bind(this), this.hlsRouter.router)
|
||||||
|
router.use('/public', this.publicRouter.router)
|
||||||
|
|
||||||
// Static path to generated nuxt
|
// Static path to generated nuxt
|
||||||
const distPath = Path.join(global.appRoot, '/client/dist')
|
const distPath = Path.join(global.appRoot, '/client/dist')
|
||||||
router.use(express.static(distPath))
|
router.use(express.static(distPath))
|
||||||
@@ -275,28 +287,24 @@ class Server {
|
|||||||
// Static folder
|
// Static folder
|
||||||
router.use(express.static(Path.join(global.appRoot, 'static')))
|
router.use(express.static(Path.join(global.appRoot, 'static')))
|
||||||
|
|
||||||
router.use('/api', this.authMiddleware.bind(this), this.apiRouter.router)
|
|
||||||
router.use('/hls', this.authMiddleware.bind(this), this.hlsRouter.router)
|
|
||||||
router.use('/public', this.publicRouter.router)
|
|
||||||
|
|
||||||
// RSS Feed temp route
|
// RSS Feed temp route
|
||||||
router.get('/feed/:slug', (req, res) => {
|
router.get('/feed/:slug', (req, res) => {
|
||||||
Logger.info(`[Server] Requesting rss feed ${req.params.slug}`)
|
Logger.info(`[Server] Requesting rss feed ${req.params.slug}`)
|
||||||
this.rssFeedManager.getFeed(req, res)
|
RssFeedManager.getFeed(req, res)
|
||||||
})
|
})
|
||||||
router.get('/feed/:slug/cover*', (req, res) => {
|
router.get('/feed/:slug/cover*', (req, res) => {
|
||||||
this.rssFeedManager.getFeedCover(req, res)
|
RssFeedManager.getFeedCover(req, res)
|
||||||
})
|
})
|
||||||
router.get('/feed/:slug/item/:episodeId/*', (req, res) => {
|
router.get('/feed/:slug/item/:episodeId/*', (req, res) => {
|
||||||
Logger.debug(`[Server] Requesting rss feed episode ${req.params.slug}/${req.params.episodeId}`)
|
Logger.debug(`[Server] Requesting rss feed episode ${req.params.slug}/${req.params.episodeId}`)
|
||||||
this.rssFeedManager.getFeedItem(req, res)
|
RssFeedManager.getFeedItem(req, res)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Auth routes
|
// Auth routes
|
||||||
await this.auth.initAuthRoutes(router)
|
await this.auth.initAuthRoutes(router)
|
||||||
|
|
||||||
// Client dynamic routes
|
// Client dynamic routes
|
||||||
const dyanimicRoutes = [
|
const dynamicRoutes = [
|
||||||
'/item/:id',
|
'/item/:id',
|
||||||
'/author/:id',
|
'/author/:id',
|
||||||
'/audiobook/:id/chapters',
|
'/audiobook/:id/chapters',
|
||||||
@@ -319,7 +327,7 @@ class Server {
|
|||||||
'/playlist/:id',
|
'/playlist/:id',
|
||||||
'/share/:slug'
|
'/share/:slug'
|
||||||
]
|
]
|
||||||
dyanimicRoutes.forEach((route) => router.get(route, (req, res) => res.sendFile(Path.join(distPath, 'index.html'))))
|
dynamicRoutes.forEach((route) => router.get(route, (req, res) => res.sendFile(Path.join(distPath, 'index.html'))))
|
||||||
|
|
||||||
router.post('/init', (req, res) => {
|
router.post('/init', (req, res) => {
|
||||||
if (Database.hasRootUser) {
|
if (Database.hasRootUser) {
|
||||||
@@ -435,19 +443,12 @@ class Server {
|
|||||||
*/
|
*/
|
||||||
async stop() {
|
async stop() {
|
||||||
Logger.info('=== Stopping Server ===')
|
Logger.info('=== Stopping Server ===')
|
||||||
await this.watcher.close()
|
Watcher.close()
|
||||||
Logger.info('Watcher Closed')
|
Logger.info('[Server] Watcher Closed')
|
||||||
|
await SocketAuthority.close()
|
||||||
return new Promise((resolve) => {
|
Logger.info('[Server] Closing HTTP Server')
|
||||||
SocketAuthority.close((err) => {
|
await new Promise((resolve) => this.server.close(resolve))
|
||||||
if (err) {
|
Logger.info('[Server] HTTP Server Closed')
|
||||||
Logger.error('Failed to close server', err)
|
|
||||||
} else {
|
|
||||||
Logger.info('Server successfully closed')
|
|
||||||
}
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Server
|
module.exports = Server
|
||||||
|
|||||||
+85
-63
@@ -14,7 +14,7 @@ const Auth = require('./Auth')
|
|||||||
class SocketAuthority {
|
class SocketAuthority {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.Server = null
|
this.Server = null
|
||||||
this.io = null
|
this.socketIoServers = []
|
||||||
|
|
||||||
/** @type {Object.<string, SocketClient>} */
|
/** @type {Object.<string, SocketClient>} */
|
||||||
this.clients = {}
|
this.clients = {}
|
||||||
@@ -89,82 +89,104 @@ class SocketAuthority {
|
|||||||
*
|
*
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
close(callback) {
|
async close() {
|
||||||
Logger.info('[SocketAuthority] Shutting down')
|
Logger.info('[SocketAuthority] closing...')
|
||||||
// This will close all open socket connections, and also close the underlying http server
|
const closePromises = this.socketIoServers.map((io) => {
|
||||||
if (this.io) this.io.close(callback)
|
return new Promise((resolve) => {
|
||||||
else callback()
|
Logger.info(`[SocketAuthority] Closing Socket.IO server: ${io.path}`)
|
||||||
|
io.close(() => {
|
||||||
|
Logger.info(`[SocketAuthority] Socket.IO server closed: ${io.path}`)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await Promise.all(closePromises)
|
||||||
|
Logger.info('[SocketAuthority] closed')
|
||||||
|
this.socketIoServers = []
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(Server) {
|
initialize(Server) {
|
||||||
this.Server = Server
|
this.Server = Server
|
||||||
|
|
||||||
this.io = new SocketIO.Server(this.Server.server, {
|
const socketIoOptions = {
|
||||||
cors: {
|
cors: {
|
||||||
origin: '*',
|
origin: '*',
|
||||||
methods: ['GET', 'POST']
|
methods: ['GET', 'POST']
|
||||||
},
|
|
||||||
path: `${global.RouterBasePath}/socket.io`
|
|
||||||
})
|
|
||||||
|
|
||||||
this.io.on('connection', (socket) => {
|
|
||||||
this.clients[socket.id] = {
|
|
||||||
id: socket.id,
|
|
||||||
socket,
|
|
||||||
connected_at: Date.now()
|
|
||||||
}
|
}
|
||||||
socket.sheepClient = this.clients[socket.id]
|
}
|
||||||
|
|
||||||
Logger.info('[SocketAuthority] Socket Connected', socket.id)
|
const ioServer = new SocketIO.Server(Server.server, socketIoOptions)
|
||||||
|
ioServer.path = '/socket.io'
|
||||||
|
this.socketIoServers.push(ioServer)
|
||||||
|
|
||||||
// Required for associating a User with a socket
|
if (global.RouterBasePath) {
|
||||||
socket.on('auth', (token) => this.authenticateSocket(socket, token))
|
// open a separate socket.io server for the router base path, keeping the original server open for legacy clients
|
||||||
|
const ioBasePath = `${global.RouterBasePath}/socket.io`
|
||||||
|
const ioBasePathServer = new SocketIO.Server(Server.server, { ...socketIoOptions, path: ioBasePath })
|
||||||
|
ioBasePathServer.path = ioBasePath
|
||||||
|
this.socketIoServers.push(ioBasePathServer)
|
||||||
|
}
|
||||||
|
|
||||||
// Scanning
|
this.socketIoServers.forEach((io) => {
|
||||||
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
io.on('connection', (socket) => {
|
||||||
|
this.clients[socket.id] = {
|
||||||
// Logs
|
id: socket.id,
|
||||||
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
socket,
|
||||||
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
connected_at: Date.now()
|
||||||
|
|
||||||
// Sent automatically from socket.io clients
|
|
||||||
socket.on('disconnect', (reason) => {
|
|
||||||
Logger.removeSocketListener(socket.id)
|
|
||||||
|
|
||||||
const _client = this.clients[socket.id]
|
|
||||||
if (!_client) {
|
|
||||||
Logger.warn(`[SocketAuthority] Socket ${socket.id} disconnect, no client (Reason: ${reason})`)
|
|
||||||
} else if (!_client.user) {
|
|
||||||
Logger.info(`[SocketAuthority] Unauth socket ${socket.id} disconnected (Reason: ${reason})`)
|
|
||||||
delete this.clients[socket.id]
|
|
||||||
} else {
|
|
||||||
Logger.debug('[SocketAuthority] User Offline ' + _client.user.username)
|
|
||||||
this.adminEmitter('user_offline', _client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
|
|
||||||
|
|
||||||
const disconnectTime = Date.now() - _client.connected_at
|
|
||||||
Logger.info(`[SocketAuthority] Socket ${socket.id} disconnected from client "${_client.user.username}" after ${disconnectTime}ms (Reason: ${reason})`)
|
|
||||||
delete this.clients[socket.id]
|
|
||||||
}
|
}
|
||||||
})
|
socket.sheepClient = this.clients[socket.id]
|
||||||
|
|
||||||
//
|
Logger.info(`[SocketAuthority] Socket Connected to ${io.path}`, socket.id)
|
||||||
// Events for testing
|
|
||||||
//
|
// Required for associating a User with a socket
|
||||||
socket.on('message_all_users', (payload) => {
|
socket.on('auth', (token) => this.authenticateSocket(socket, token))
|
||||||
// admin user can send a message to all authenticated users
|
|
||||||
// displays on the web app as a toast
|
// Scanning
|
||||||
const client = this.clients[socket.id] || {}
|
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
||||||
if (client.user?.isAdminOrUp) {
|
|
||||||
this.emitter('admin_message', payload.message || '')
|
// Logs
|
||||||
} else {
|
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
||||||
Logger.error(`[SocketAuthority] Non-admin user sent the message_all_users event`)
|
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
||||||
}
|
|
||||||
})
|
// Sent automatically from socket.io clients
|
||||||
socket.on('ping', () => {
|
socket.on('disconnect', (reason) => {
|
||||||
const client = this.clients[socket.id] || {}
|
Logger.removeSocketListener(socket.id)
|
||||||
const user = client.user || {}
|
|
||||||
Logger.debug(`[SocketAuthority] Received ping from socket ${user.username || 'No User'}`)
|
const _client = this.clients[socket.id]
|
||||||
socket.emit('pong')
|
if (!_client) {
|
||||||
|
Logger.warn(`[SocketAuthority] Socket ${socket.id} disconnect, no client (Reason: ${reason})`)
|
||||||
|
} else if (!_client.user) {
|
||||||
|
Logger.info(`[SocketAuthority] Unauth socket ${socket.id} disconnected (Reason: ${reason})`)
|
||||||
|
delete this.clients[socket.id]
|
||||||
|
} else {
|
||||||
|
Logger.debug('[SocketAuthority] User Offline ' + _client.user.username)
|
||||||
|
this.adminEmitter('user_offline', _client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
|
||||||
|
|
||||||
|
const disconnectTime = Date.now() - _client.connected_at
|
||||||
|
Logger.info(`[SocketAuthority] Socket ${socket.id} disconnected from client "${_client.user.username}" after ${disconnectTime}ms (Reason: ${reason})`)
|
||||||
|
delete this.clients[socket.id]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//
|
||||||
|
// Events for testing
|
||||||
|
//
|
||||||
|
socket.on('message_all_users', (payload) => {
|
||||||
|
// admin user can send a message to all authenticated users
|
||||||
|
// displays on the web app as a toast
|
||||||
|
const client = this.clients[socket.id] || {}
|
||||||
|
if (client.user?.isAdminOrUp) {
|
||||||
|
this.emitter('admin_message', payload.message || '')
|
||||||
|
} else {
|
||||||
|
Logger.error(`[SocketAuthority] Non-admin user sent the message_all_users event`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
socket.on('ping', () => {
|
||||||
|
const client = this.clients[socket.id] || {}
|
||||||
|
const user = client.user || {}
|
||||||
|
Logger.debug(`[SocketAuthority] Received ping from socket ${user.username || 'No User'}`)
|
||||||
|
socket.emit('pong')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-3
@@ -2,7 +2,6 @@ const Path = require('path')
|
|||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events')
|
||||||
const Watcher = require('./libs/watcher/watcher')
|
const Watcher = require('./libs/watcher/watcher')
|
||||||
const Logger = require('./Logger')
|
const Logger = require('./Logger')
|
||||||
const LibraryScanner = require('./scanner/LibraryScanner')
|
|
||||||
const Task = require('./objects/Task')
|
const Task = require('./objects/Task')
|
||||||
const TaskManager = require('./managers/TaskManager')
|
const TaskManager = require('./managers/TaskManager')
|
||||||
|
|
||||||
@@ -31,6 +30,8 @@ class FolderWatcher extends EventEmitter {
|
|||||||
|
|
||||||
this.filesBeingAdded = new Set()
|
this.filesBeingAdded = new Set()
|
||||||
|
|
||||||
|
/** @type {Set<string>} */
|
||||||
|
this.ignoreFilePathsDownloading = new Set()
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
this.ignoreDirs = []
|
this.ignoreDirs = []
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
@@ -333,7 +334,7 @@ class FolderWatcher extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.pendingFileUpdates.length) {
|
if (this.pendingFileUpdates.length) {
|
||||||
LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask)
|
this.emit('scanFilesChanged', this.pendingFileUpdates, this.pendingTask)
|
||||||
} else {
|
} else {
|
||||||
const taskFinishedString = {
|
const taskFinishedString = {
|
||||||
text: 'No files to scan',
|
text: 'No files to scan',
|
||||||
@@ -348,12 +349,29 @@ class FolderWatcher extends EventEmitter {
|
|||||||
}, this.pendingDelay)
|
}, this.pendingDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
checkShouldIgnorePath(path) {
|
checkShouldIgnorePath(path) {
|
||||||
return !!this.ignoreDirs.find((dirpath) => {
|
return !!this.ignoreDirs.find((dirpath) => {
|
||||||
return isSameOrSubPath(dirpath, path)
|
return isSameOrSubPath(dirpath, path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When scanning a library item folder these files should be ignored
|
||||||
|
* Either a podcast episode downloading or a file that is pending by the watcher
|
||||||
|
*
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
checkShouldIgnoreFilePath(path) {
|
||||||
|
if (this.pendingFilePaths.includes(path)) return true
|
||||||
|
return this.ignoreFilePathsDownloading.has(path)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert to POSIX and remove trailing slash
|
* Convert to POSIX and remove trailing slash
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
@@ -409,4 +427,4 @@ class FolderWatcher extends EventEmitter {
|
|||||||
}, 5000)
|
}, 5000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = FolderWatcher
|
module.exports = new FolderWatcher()
|
||||||
|
|||||||
@@ -381,16 +381,23 @@ class AuthorController {
|
|||||||
*/
|
*/
|
||||||
async getImage(req, res) {
|
async getImage(req, res) {
|
||||||
const {
|
const {
|
||||||
query: { width, height, format, raw },
|
query: { width, height, format, raw }
|
||||||
author
|
|
||||||
} = req
|
} = req
|
||||||
|
|
||||||
if (!author.imagePath || !(await fs.pathExists(author.imagePath))) {
|
const authorId = req.params.id
|
||||||
Logger.warn(`[AuthorController] Author "${author.name}" has invalid imagePath: ${author.imagePath}`)
|
|
||||||
return res.sendStatus(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (raw) {
|
if (raw) {
|
||||||
|
const author = await Database.authorModel.findByPk(authorId)
|
||||||
|
if (!author) {
|
||||||
|
Logger.warn(`[AuthorController] Author "${authorId}" not found`)
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!author.imagePath || !(await fs.pathExists(author.imagePath))) {
|
||||||
|
Logger.warn(`[AuthorController] Author "${author.name}" has invalid imagePath: ${author.imagePath}`)
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
|
|
||||||
return res.sendFile(author.imagePath)
|
return res.sendFile(author.imagePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +406,7 @@ class AuthorController {
|
|||||||
height: height ? parseInt(height) : null,
|
height: height ? parseInt(height) : null,
|
||||||
width: width ? parseInt(width) : null
|
width: width ? parseInt(width) : null
|
||||||
}
|
}
|
||||||
return CacheManager.handleAuthorCache(res, author, options)
|
return CacheManager.handleAuthorCache(res, authorId, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const Logger = require('../Logger')
|
|||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
|
||||||
|
const RssFeedManager = require('../managers/RssFeedManager')
|
||||||
const Collection = require('../objects/Collection')
|
const Collection = require('../objects/Collection')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,6 +116,7 @@ class CollectionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If books array is passed in then update order in collection
|
// If books array is passed in then update order in collection
|
||||||
|
let collectionBooksUpdated = false
|
||||||
if (req.body.books?.length) {
|
if (req.body.books?.length) {
|
||||||
const collectionBooks = await req.collection.getCollectionBooks({
|
const collectionBooks = await req.collection.getCollectionBooks({
|
||||||
include: {
|
include: {
|
||||||
@@ -133,9 +135,15 @@ class CollectionController {
|
|||||||
await collectionBooks[i].update({
|
await collectionBooks[i].update({
|
||||||
order: i + 1
|
order: i + 1
|
||||||
})
|
})
|
||||||
wasUpdated = true
|
collectionBooksUpdated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (collectionBooksUpdated) {
|
||||||
|
req.collection.changed('updatedAt', true)
|
||||||
|
await req.collection.save()
|
||||||
|
wasUpdated = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonExpanded = await req.collection.getOldJsonExpanded()
|
const jsonExpanded = await req.collection.getOldJsonExpanded()
|
||||||
@@ -148,6 +156,8 @@ class CollectionController {
|
|||||||
/**
|
/**
|
||||||
* DELETE: /api/collections/:id
|
* DELETE: /api/collections/:id
|
||||||
*
|
*
|
||||||
|
* @this {import('../routers/ApiRouter')}
|
||||||
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {RequestWithUser} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
@@ -155,7 +165,7 @@ class CollectionController {
|
|||||||
const jsonExpanded = await req.collection.getOldJsonExpanded()
|
const jsonExpanded = await req.collection.getOldJsonExpanded()
|
||||||
|
|
||||||
// Close rss feed - remove from db and emit socket event
|
// Close rss feed - remove from db and emit socket event
|
||||||
await this.rssFeedManager.closeFeedForEntityId(req.collection.id)
|
await RssFeedManager.closeFeedForEntityId(req.collection.id)
|
||||||
|
|
||||||
await req.collection.destroy()
|
await req.collection.destroy()
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ const naturalSort = createNewSortInstance({
|
|||||||
const LibraryScanner = require('../scanner/LibraryScanner')
|
const LibraryScanner = require('../scanner/LibraryScanner')
|
||||||
const Scanner = require('../scanner/Scanner')
|
const Scanner = require('../scanner/Scanner')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
const Watcher = require('../Watcher')
|
||||||
|
const RssFeedManager = require('../managers/RssFeedManager')
|
||||||
|
|
||||||
const libraryFilters = require('../utils/queries/libraryFilters')
|
const libraryFilters = require('../utils/queries/libraryFilters')
|
||||||
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
|
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
|
||||||
const authorFilters = require('../utils/queries/authorFilters')
|
const authorFilters = require('../utils/queries/authorFilters')
|
||||||
@@ -158,7 +161,7 @@ class LibraryController {
|
|||||||
SocketAuthority.emitter('library_added', library.toOldJSON(), userFilter)
|
SocketAuthority.emitter('library_added', library.toOldJSON(), userFilter)
|
||||||
|
|
||||||
// Add library watcher
|
// Add library watcher
|
||||||
this.watcher.addLibrary(library)
|
Watcher.addLibrary(library)
|
||||||
|
|
||||||
res.json(library.toOldJSON())
|
res.json(library.toOldJSON())
|
||||||
}
|
}
|
||||||
@@ -235,12 +238,14 @@ class LibraryController {
|
|||||||
for (const key of keysToCheck) {
|
for (const key of keysToCheck) {
|
||||||
if (!req.body[key]) continue
|
if (!req.body[key]) continue
|
||||||
if (typeof req.body[key] !== 'string') {
|
if (typeof req.body[key] !== 'string') {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. ${key} must be a string`)
|
||||||
return res.status(400).send(`Invalid request. ${key} must be a string`)
|
return res.status(400).send(`Invalid request. ${key} must be a string`)
|
||||||
}
|
}
|
||||||
updatePayload[key] = req.body[key]
|
updatePayload[key] = req.body[key]
|
||||||
}
|
}
|
||||||
if (req.body.displayOrder !== undefined) {
|
if (req.body.displayOrder !== undefined) {
|
||||||
if (isNaN(req.body.displayOrder)) {
|
if (isNaN(req.body.displayOrder)) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. displayOrder must be a number`)
|
||||||
return res.status(400).send('Invalid request. displayOrder must be a number')
|
return res.status(400).send('Invalid request. displayOrder must be a number')
|
||||||
}
|
}
|
||||||
updatePayload.displayOrder = req.body.displayOrder
|
updatePayload.displayOrder = req.body.displayOrder
|
||||||
@@ -255,18 +260,29 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate settings
|
// Validate settings
|
||||||
|
const defaultLibrarySettings = Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType)
|
||||||
const updatedSettings = {
|
const updatedSettings = {
|
||||||
...(req.library.settings || Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType))
|
...(req.library.settings || defaultLibrarySettings)
|
||||||
}
|
}
|
||||||
|
// In case new settings are added in the future, ensure all settings are present
|
||||||
|
for (const key in defaultLibrarySettings) {
|
||||||
|
if (updatedSettings[key] === undefined) {
|
||||||
|
updatedSettings[key] = defaultLibrarySettings[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let hasUpdates = false
|
let hasUpdates = false
|
||||||
let hasUpdatedDisableWatcher = false
|
let hasUpdatedDisableWatcher = false
|
||||||
let hasUpdatedScanCron = false
|
let hasUpdatedScanCron = false
|
||||||
if (req.body.settings) {
|
if (req.body.settings) {
|
||||||
for (const key in req.body.settings) {
|
for (const key in req.body.settings) {
|
||||||
if (updatedSettings[key] === undefined) continue
|
if (!Object.keys(defaultLibrarySettings).includes(key)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (key === 'metadataPrecedence') {
|
if (key === 'metadataPrecedence') {
|
||||||
if (!Array.isArray(req.body.settings[key])) {
|
if (!Array.isArray(req.body.settings[key])) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Settings "metadataPrecedence" must be an array`)
|
||||||
return res.status(400).send('Invalid request. Settings "metadataPrecedence" must be an array')
|
return res.status(400).send('Invalid request. Settings "metadataPrecedence" must be an array')
|
||||||
}
|
}
|
||||||
if (JSON.stringify(req.body.settings[key]) !== JSON.stringify(updatedSettings[key])) {
|
if (JSON.stringify(req.body.settings[key]) !== JSON.stringify(updatedSettings[key])) {
|
||||||
@@ -276,6 +292,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
} else if (key === 'autoScanCronExpression' || key === 'podcastSearchRegion') {
|
} else if (key === 'autoScanCronExpression' || key === 'podcastSearchRegion') {
|
||||||
if (req.body.settings[key] !== null && typeof req.body.settings[key] !== 'string') {
|
if (req.body.settings[key] !== null && typeof req.body.settings[key] !== 'string') {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Settings "${key}" must be a string`)
|
||||||
return res.status(400).send(`Invalid request. Settings "${key}" must be a string`)
|
return res.status(400).send(`Invalid request. Settings "${key}" must be a string`)
|
||||||
}
|
}
|
||||||
if (req.body.settings[key] !== updatedSettings[key]) {
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
@@ -285,8 +302,35 @@ class LibraryController {
|
|||||||
updatedSettings[key] = req.body.settings[key]
|
updatedSettings[key] = req.body.settings[key]
|
||||||
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
}
|
}
|
||||||
|
} else if (key === 'markAsFinishedPercentComplete') {
|
||||||
|
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be a number`)
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
|
||||||
|
} else if (req.body.settings[key] !== null && (Number(req.body.settings[key]) < 0 || Number(req.body.settings[key]) > 100)) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be between 0 and 100`)
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be between 0 and 100`)
|
||||||
|
}
|
||||||
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
|
hasUpdates = true
|
||||||
|
updatedSettings[key] = Number(req.body.settings[key])
|
||||||
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
|
}
|
||||||
|
} else if (key === 'markAsFinishedTimeRemaining') {
|
||||||
|
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be a number`)
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
|
||||||
|
} else if (req.body.settings[key] !== null && Number(req.body.settings[key]) < 0) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be greater than or equal to 0`)
|
||||||
|
return res.status(400).send(`Invalid request. Setting "${key}" must be greater than or equal to 0`)
|
||||||
|
}
|
||||||
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
|
hasUpdates = true
|
||||||
|
updatedSettings[key] = Number(req.body.settings[key])
|
||||||
|
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof req.body.settings[key] !== typeof updatedSettings[key]) {
|
if (typeof req.body.settings[key] !== typeof updatedSettings[key]) {
|
||||||
|
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
|
||||||
return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
|
return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
|
||||||
}
|
}
|
||||||
if (req.body.settings[key] !== updatedSettings[key]) {
|
if (req.body.settings[key] !== updatedSettings[key]) {
|
||||||
@@ -328,6 +372,7 @@ class LibraryController {
|
|||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
Logger.error(`[LibraryController] Invalid folder directory "${path}"`)
|
||||||
return res.status(400).send(`Invalid folder directory "${path}"`)
|
return res.status(400).send(`Invalid folder directory "${path}"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,19 +402,48 @@ class LibraryController {
|
|||||||
model: Database.podcastEpisodeModel,
|
model: Database.podcastEpisodeModel,
|
||||||
attributes: ['id']
|
attributes: ['id']
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.bookModel,
|
||||||
|
attributes: ['id'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.bookAuthorModel,
|
||||||
|
attributes: ['authorId']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.bookSeriesModel,
|
||||||
|
attributes: ['seriesId']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
Logger.info(`[LibraryController] Removed folder "${folder.path}" from library "${req.library.name}" with ${libraryItemsInFolder.length} library items`)
|
Logger.info(`[LibraryController] Removed folder "${folder.path}" from library "${req.library.name}" with ${libraryItemsInFolder.length} library items`)
|
||||||
|
const seriesIds = []
|
||||||
|
const authorIds = []
|
||||||
for (const libraryItem of libraryItemsInFolder) {
|
for (const libraryItem of libraryItemsInFolder) {
|
||||||
let mediaItemIds = []
|
let mediaItemIds = []
|
||||||
if (req.library.isPodcast) {
|
if (req.library.isPodcast) {
|
||||||
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
||||||
} else {
|
} else {
|
||||||
mediaItemIds.push(libraryItem.mediaId)
|
mediaItemIds.push(libraryItem.mediaId)
|
||||||
|
if (libraryItem.media.bookAuthors.length) {
|
||||||
|
authorIds.push(...libraryItem.media.bookAuthors.map((ba) => ba.authorId))
|
||||||
|
}
|
||||||
|
if (libraryItem.media.bookSeries.length) {
|
||||||
|
seriesIds.push(...libraryItem.media.bookSeries.map((bs) => bs.seriesId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from folder "${folder.path}"`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from folder "${folder.path}"`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove folder
|
// Remove folder
|
||||||
@@ -398,7 +472,7 @@ class LibraryController {
|
|||||||
req.library.libraryFolders = await req.library.getLibraryFolders()
|
req.library.libraryFolders = await req.library.getLibraryFolders()
|
||||||
|
|
||||||
// Update watcher
|
// Update watcher
|
||||||
this.watcher.updateLibrary(req.library)
|
Watcher.updateLibrary(req.library)
|
||||||
|
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
@@ -424,7 +498,7 @@ class LibraryController {
|
|||||||
*/
|
*/
|
||||||
async delete(req, res) {
|
async delete(req, res) {
|
||||||
// Remove library watcher
|
// Remove library watcher
|
||||||
this.watcher.removeLibrary(req.library)
|
Watcher.removeLibrary(req.library)
|
||||||
|
|
||||||
// Remove collections for library
|
// Remove collections for library
|
||||||
const numCollectionsRemoved = await Database.collectionModel.removeAllForLibrary(req.library.id)
|
const numCollectionsRemoved = await Database.collectionModel.removeAllForLibrary(req.library.id)
|
||||||
@@ -458,11 +532,24 @@ class LibraryController {
|
|||||||
mediaItemIds.push(libraryItem.mediaId)
|
mediaItemIds.push(libraryItem.mediaId)
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from library "${req.library.name}"`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from library "${req.library.name}"`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set PlaybackSessions libraryId to null
|
||||||
|
const [sessionsUpdated] = await Database.playbackSessionModel.update(
|
||||||
|
{
|
||||||
|
libraryId: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
libraryId: req.library.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Logger.info(`[LibraryController] Updated ${sessionsUpdated} playback sessions to remove library id`)
|
||||||
|
|
||||||
const libraryJson = req.library.toOldJSON()
|
const libraryJson = req.library.toOldJSON()
|
||||||
await Database.removeLibrary(req.library.id)
|
await req.library.destroy()
|
||||||
|
|
||||||
// Re-order libraries
|
// Re-order libraries
|
||||||
await Database.libraryModel.resetDisplayOrder()
|
await Database.libraryModel.resetDisplayOrder()
|
||||||
@@ -524,6 +611,8 @@ class LibraryController {
|
|||||||
* DELETE: /api/libraries/:id/issues
|
* DELETE: /api/libraries/:id/issues
|
||||||
* Remove all library items missing or invalid
|
* Remove all library items missing or invalid
|
||||||
*
|
*
|
||||||
|
* @this {import('../routers/ApiRouter')}
|
||||||
|
*
|
||||||
* @param {LibraryControllerRequest} req
|
* @param {LibraryControllerRequest} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
@@ -549,6 +638,20 @@ class LibraryController {
|
|||||||
model: Database.podcastEpisodeModel,
|
model: Database.podcastEpisodeModel,
|
||||||
attributes: ['id']
|
attributes: ['id']
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.bookModel,
|
||||||
|
attributes: ['id'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.bookAuthorModel,
|
||||||
|
attributes: ['authorId']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.bookSeriesModel,
|
||||||
|
attributes: ['seriesId']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -559,15 +662,30 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger.info(`[LibraryController] Removing ${libraryItemsWithIssues.length} items with issues`)
|
Logger.info(`[LibraryController] Removing ${libraryItemsWithIssues.length} items with issues`)
|
||||||
|
const authorIds = []
|
||||||
|
const seriesIds = []
|
||||||
for (const libraryItem of libraryItemsWithIssues) {
|
for (const libraryItem of libraryItemsWithIssues) {
|
||||||
let mediaItemIds = []
|
let mediaItemIds = []
|
||||||
if (req.library.isPodcast) {
|
if (req.library.isPodcast) {
|
||||||
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
||||||
} else {
|
} else {
|
||||||
mediaItemIds.push(libraryItem.mediaId)
|
mediaItemIds.push(libraryItem.mediaId)
|
||||||
|
if (libraryItem.media.bookAuthors.length) {
|
||||||
|
authorIds.push(...libraryItem.media.bookAuthors.map((ba) => ba.authorId))
|
||||||
|
}
|
||||||
|
if (libraryItem.media.bookSeries.length) {
|
||||||
|
seriesIds.push(...libraryItem.media.bookSeries.map((bs) => bs.seriesId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" with issue`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" with issue`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set numIssues to 0 for library filter data
|
// Set numIssues to 0 for library filter data
|
||||||
@@ -643,8 +761,8 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (include.includes('rssfeed')) {
|
if (include.includes('rssfeed')) {
|
||||||
const feedObj = await this.rssFeedManager.findFeedForEntityId(seriesJson.id)
|
const feedObj = await RssFeedManager.findFeedForEntityId(seriesJson.id)
|
||||||
seriesJson.rssFeed = feedObj?.toJSONMinified() || null
|
seriesJson.rssFeed = feedObj?.toOldJSONMinified() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(seriesJson)
|
res.json(seriesJson)
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUti
|
|||||||
const LibraryItemScanner = require('../scanner/LibraryItemScanner')
|
const LibraryItemScanner = require('../scanner/LibraryItemScanner')
|
||||||
const AudioFileScanner = require('../scanner/AudioFileScanner')
|
const AudioFileScanner = require('../scanner/AudioFileScanner')
|
||||||
const Scanner = require('../scanner/Scanner')
|
const Scanner = require('../scanner/Scanner')
|
||||||
|
|
||||||
|
const RssFeedManager = require('../managers/RssFeedManager')
|
||||||
const CacheManager = require('../managers/CacheManager')
|
const CacheManager = require('../managers/CacheManager')
|
||||||
const CoverManager = require('../managers/CoverManager')
|
const CoverManager = require('../managers/CoverManager')
|
||||||
const ShareManager = require('../managers/ShareManager')
|
const ShareManager = require('../managers/ShareManager')
|
||||||
@@ -48,8 +50,8 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (includeEntities.includes('rssfeed')) {
|
if (includeEntities.includes('rssfeed')) {
|
||||||
const feedData = await this.rssFeedManager.findFeedForEntityId(item.id)
|
const feedData = await RssFeedManager.findFeedForEntityId(item.id)
|
||||||
item.rssFeed = feedData?.toJSONMinified() || null
|
item.rssFeed = feedData?.toOldJSONMinified() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {
|
if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {
|
||||||
@@ -96,6 +98,8 @@ class LibraryItemController {
|
|||||||
* Optional query params:
|
* Optional query params:
|
||||||
* ?hard=1
|
* ?hard=1
|
||||||
*
|
*
|
||||||
|
* @this {import('../routers/ApiRouter')}
|
||||||
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {RequestWithUser} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
@@ -103,18 +107,50 @@ class LibraryItemController {
|
|||||||
const hardDelete = req.query.hard == 1 // Delete from file system
|
const hardDelete = req.query.hard == 1 // Delete from file system
|
||||||
const libraryItemPath = req.libraryItem.path
|
const libraryItemPath = req.libraryItem.path
|
||||||
|
|
||||||
const mediaItemIds = req.libraryItem.mediaType === 'podcast' ? req.libraryItem.media.episodes.map((ep) => ep.id) : [req.libraryItem.media.id]
|
const mediaItemIds = []
|
||||||
await this.handleDeleteLibraryItem(req.libraryItem.mediaType, req.libraryItem.id, mediaItemIds)
|
const authorIds = []
|
||||||
|
const seriesIds = []
|
||||||
|
if (req.libraryItem.isPodcast) {
|
||||||
|
mediaItemIds.push(...req.libraryItem.media.episodes.map((ep) => ep.id))
|
||||||
|
} else {
|
||||||
|
mediaItemIds.push(req.libraryItem.media.id)
|
||||||
|
if (req.libraryItem.media.metadata.authors?.length) {
|
||||||
|
authorIds.push(...req.libraryItem.media.metadata.authors.map((au) => au.id))
|
||||||
|
}
|
||||||
|
if (req.libraryItem.media.metadata.series?.length) {
|
||||||
|
seriesIds.push(...req.libraryItem.media.metadata.series.map((se) => se.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.handleDeleteLibraryItem(req.libraryItem.id, mediaItemIds)
|
||||||
if (hardDelete) {
|
if (hardDelete) {
|
||||||
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
await fs.remove(libraryItemPath).catch((error) => {
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
|
}
|
||||||
|
|
||||||
await Database.resetLibraryIssuesFilterData(req.libraryItem.libraryId)
|
await Database.resetLibraryIssuesFilterData(req.libraryItem.libraryId)
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static handleDownloadError(error, res) {
|
||||||
|
if (!res.headersSent) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
return res.status(404).send('File not found')
|
||||||
|
} else {
|
||||||
|
return res.status(500).send('Download failed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET: /api/items/:id/download
|
* GET: /api/items/:id/download
|
||||||
* Download library item. Zip file if multiple files.
|
* Download library item. Zip file if multiple files.
|
||||||
@@ -122,7 +158,7 @@ class LibraryItemController {
|
|||||||
* @param {RequestWithUser} req
|
* @param {RequestWithUser} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
download(req, res) {
|
async download(req, res) {
|
||||||
if (!req.user.canDownload) {
|
if (!req.user.canDownload) {
|
||||||
Logger.warn(`User "${req.user.username}" attempted to download without permission`)
|
Logger.warn(`User "${req.user.username}" attempted to download without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
@@ -130,21 +166,26 @@ class LibraryItemController {
|
|||||||
const libraryItemPath = req.libraryItem.path
|
const libraryItemPath = req.libraryItem.path
|
||||||
const itemTitle = req.libraryItem.media.metadata.title
|
const itemTitle = req.libraryItem.media.metadata.title
|
||||||
|
|
||||||
// If library item is a single file in root dir then no need to zip
|
|
||||||
if (req.libraryItem.isFile) {
|
|
||||||
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
|
|
||||||
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(libraryItemPath))
|
|
||||||
if (audioMimeType) {
|
|
||||||
res.setHeader('Content-Type', audioMimeType)
|
|
||||||
}
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
|
||||||
res.download(libraryItemPath, req.libraryItem.relPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
||||||
const filename = `${itemTitle}.zip`
|
|
||||||
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
|
try {
|
||||||
|
// If library item is a single file in root dir then no need to zip
|
||||||
|
if (req.libraryItem.isFile) {
|
||||||
|
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
|
||||||
|
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(libraryItemPath))
|
||||||
|
if (audioMimeType) {
|
||||||
|
res.setHeader('Content-Type', audioMimeType)
|
||||||
|
}
|
||||||
|
await new Promise((resolve, reject) => res.download(libraryItemPath, req.libraryItem.relPath, (error) => (error ? reject(error) : resolve())))
|
||||||
|
} else {
|
||||||
|
const filename = `${itemTitle}.zip`
|
||||||
|
await zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
|
||||||
|
}
|
||||||
|
Logger.info(`[LibraryItemController] Downloaded item "${itemTitle}" at "${libraryItemPath}"`)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(`[LibraryItemController] Download failed for item "${itemTitle}" at "${libraryItemPath}"`, error)
|
||||||
|
LibraryItemController.handleDownloadError(error, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,15 +238,6 @@ class LibraryItemController {
|
|||||||
if (hasUpdates) {
|
if (hasUpdates) {
|
||||||
libraryItem.updatedAt = Date.now()
|
libraryItem.updatedAt = Date.now()
|
||||||
|
|
||||||
if (seriesRemoved.length) {
|
|
||||||
// Check remove empty series
|
|
||||||
Logger.debug(`[LibraryItemController] Series was removed from book. Check if series is now empty.`)
|
|
||||||
await this.checkRemoveEmptySeries(
|
|
||||||
libraryItem.media.id,
|
|
||||||
seriesRemoved.map((se) => se.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPodcastAutoDownloadUpdated) {
|
if (isPodcastAutoDownloadUpdated) {
|
||||||
this.cronManager.checkUpdatePodcastCron(libraryItem)
|
this.cronManager.checkUpdatePodcastCron(libraryItem)
|
||||||
}
|
}
|
||||||
@@ -217,10 +249,12 @@ class LibraryItemController {
|
|||||||
if (authorsRemoved.length) {
|
if (authorsRemoved.length) {
|
||||||
// Check remove empty authors
|
// Check remove empty authors
|
||||||
Logger.debug(`[LibraryItemController] Authors were removed from book. Check if authors are now empty.`)
|
Logger.debug(`[LibraryItemController] Authors were removed from book. Check if authors are now empty.`)
|
||||||
await this.checkRemoveAuthorsWithNoBooks(
|
await this.checkRemoveAuthorsWithNoBooks(authorsRemoved.map((au) => au.id))
|
||||||
libraryItem.libraryId,
|
}
|
||||||
authorsRemoved.map((au) => au.id)
|
if (seriesRemoved.length) {
|
||||||
)
|
// Check remove empty series
|
||||||
|
Logger.debug(`[LibraryItemController] Series were removed from book. Check if series are now empty.`)
|
||||||
|
await this.checkRemoveEmptySeries(seriesRemoved.map((se) => se.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.json({
|
res.json({
|
||||||
@@ -327,44 +361,25 @@ class LibraryItemController {
|
|||||||
query: { width, height, format, raw }
|
query: { width, height, format, raw }
|
||||||
} = req
|
} = req
|
||||||
|
|
||||||
const libraryItem = await Database.libraryItemModel.findByPk(req.params.id, {
|
|
||||||
attributes: ['id', 'mediaType', 'mediaId', 'libraryId'],
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Database.bookModel,
|
|
||||||
attributes: ['id', 'coverPath', 'tags', 'explicit']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: Database.podcastModel,
|
|
||||||
attributes: ['id', 'coverPath', 'tags', 'explicit']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
if (!libraryItem) {
|
|
||||||
Logger.warn(`[LibraryItemController] getCover: Library item "${req.params.id}" does not exist`)
|
|
||||||
return res.sendStatus(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user can access this library item
|
|
||||||
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
|
|
||||||
return res.sendStatus(403)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if library item media has a cover path
|
|
||||||
if (!libraryItem.media.coverPath || !(await fs.pathExists(libraryItem.media.coverPath))) {
|
|
||||||
return res.sendStatus(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.query.ts) res.set('Cache-Control', 'private, max-age=86400')
|
if (req.query.ts) res.set('Cache-Control', 'private, max-age=86400')
|
||||||
|
|
||||||
|
const libraryItemId = req.params.id
|
||||||
|
if (!libraryItemId) {
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
if (raw) {
|
if (raw) {
|
||||||
|
const coverPath = await Database.libraryItemModel.getCoverPath(libraryItemId)
|
||||||
|
if (!coverPath || !(await fs.pathExists(coverPath))) {
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
// any value
|
// any value
|
||||||
if (global.XAccel) {
|
if (global.XAccel) {
|
||||||
const encodedURI = encodeUriPath(global.XAccel + libraryItem.media.coverPath)
|
const encodedURI = encodeUriPath(global.XAccel + coverPath)
|
||||||
Logger.debug(`Use X-Accel to serve static file ${encodedURI}`)
|
Logger.debug(`Use X-Accel to serve static file ${encodedURI}`)
|
||||||
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
|
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
|
||||||
}
|
}
|
||||||
return res.sendFile(libraryItem.media.coverPath)
|
return res.sendFile(coverPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
@@ -372,7 +387,7 @@ class LibraryItemController {
|
|||||||
height: height ? parseInt(height) : null,
|
height: height ? parseInt(height) : null,
|
||||||
width: width ? parseInt(width) : null
|
width: width ? parseInt(width) : null
|
||||||
}
|
}
|
||||||
return CacheManager.handleCoverCache(res, libraryItem.id, libraryItem.media.coverPath, options)
|
return CacheManager.handleCoverCache(res, libraryItemId, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -454,6 +469,8 @@ class LibraryItemController {
|
|||||||
* Optional query params:
|
* Optional query params:
|
||||||
* ?hard=1
|
* ?hard=1
|
||||||
*
|
*
|
||||||
|
* @this {import('../routers/ApiRouter')}
|
||||||
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {RequestWithUser} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
@@ -481,14 +498,33 @@ class LibraryItemController {
|
|||||||
for (const libraryItem of itemsToDelete) {
|
for (const libraryItem of itemsToDelete) {
|
||||||
const libraryItemPath = libraryItem.path
|
const libraryItemPath = libraryItem.path
|
||||||
Logger.info(`[LibraryItemController] (${hardDelete ? 'Hard' : 'Soft'}) deleting Library Item "${libraryItem.media.metadata.title}" with id "${libraryItem.id}"`)
|
Logger.info(`[LibraryItemController] (${hardDelete ? 'Hard' : 'Soft'}) deleting Library Item "${libraryItem.media.metadata.title}" with id "${libraryItem.id}"`)
|
||||||
const mediaItemIds = libraryItem.mediaType === 'podcast' ? libraryItem.media.episodes.map((ep) => ep.id) : [libraryItem.media.id]
|
const mediaItemIds = []
|
||||||
await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds)
|
const seriesIds = []
|
||||||
|
const authorIds = []
|
||||||
|
if (libraryItem.isPodcast) {
|
||||||
|
mediaItemIds.push(...libraryItem.media.episodes.map((ep) => ep.id))
|
||||||
|
} else {
|
||||||
|
mediaItemIds.push(libraryItem.media.id)
|
||||||
|
if (libraryItem.media.metadata.series?.length) {
|
||||||
|
seriesIds.push(...libraryItem.media.metadata.series.map((se) => se.id))
|
||||||
|
}
|
||||||
|
if (libraryItem.media.metadata.authors?.length) {
|
||||||
|
authorIds.push(...libraryItem.media.metadata.authors.map((au) => au.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
||||||
if (hardDelete) {
|
if (hardDelete) {
|
||||||
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
await fs.remove(libraryItemPath).catch((error) => {
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
Logger.error(`[LibraryItemController] Failed to delete library item from file system at "${libraryItemPath}"`, error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
|
}
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Database.resetLibraryIssuesFilterData(libraryId)
|
await Database.resetLibraryIssuesFilterData(libraryId)
|
||||||
@@ -498,48 +534,74 @@ class LibraryItemController {
|
|||||||
/**
|
/**
|
||||||
* POST: /api/items/batch/update
|
* POST: /api/items/batch/update
|
||||||
*
|
*
|
||||||
|
* @this {import('../routers/ApiRouter')}
|
||||||
|
*
|
||||||
* @param {RequestWithUser} req
|
* @param {RequestWithUser} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
async batchUpdate(req, res) {
|
async batchUpdate(req, res) {
|
||||||
const updatePayloads = req.body
|
const updatePayloads = req.body
|
||||||
if (!updatePayloads?.length) {
|
if (!Array.isArray(updatePayloads) || !updatePayloads.length) {
|
||||||
return res.sendStatus(500)
|
Logger.error(`[LibraryItemController] Batch update failed. Invalid payload`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that each update payload has a unique library item id
|
||||||
|
const libraryItemIds = [...new Set(updatePayloads.map((up) => up?.id).filter((id) => id))]
|
||||||
|
if (!libraryItemIds.length || libraryItemIds.length !== updatePayloads.length) {
|
||||||
|
Logger.error(`[LibraryItemController] Batch update failed. Each update payload must have a unique library item id`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all library items to update
|
||||||
|
const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({
|
||||||
|
id: libraryItemIds
|
||||||
|
})
|
||||||
|
if (updatePayloads.length !== libraryItems.length) {
|
||||||
|
Logger.error(`[LibraryItemController] Batch update failed. Not all library items found`)
|
||||||
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemsUpdated = 0
|
let itemsUpdated = 0
|
||||||
|
|
||||||
|
const seriesIdsRemoved = []
|
||||||
|
const authorIdsRemoved = []
|
||||||
|
|
||||||
for (const updatePayload of updatePayloads) {
|
for (const updatePayload of updatePayloads) {
|
||||||
const mediaPayload = updatePayload.mediaPayload
|
const mediaPayload = updatePayload.mediaPayload
|
||||||
const libraryItem = await Database.libraryItemModel.getOldById(updatePayload.id)
|
const libraryItem = libraryItems.find((li) => li.id === updatePayload.id)
|
||||||
if (!libraryItem) return null
|
|
||||||
|
|
||||||
await this.createAuthorsAndSeriesForItemUpdate(mediaPayload, libraryItem.libraryId)
|
await this.createAuthorsAndSeriesForItemUpdate(mediaPayload, libraryItem.libraryId)
|
||||||
|
|
||||||
let seriesRemoved = []
|
if (libraryItem.isBook) {
|
||||||
if (libraryItem.isBook && mediaPayload.metadata?.series) {
|
if (Array.isArray(mediaPayload.metadata?.series)) {
|
||||||
const seriesIdsInUpdate = (mediaPayload.metadata?.series || []).map((se) => se.id)
|
const seriesIdsInUpdate = mediaPayload.metadata.series.map((se) => se.id)
|
||||||
seriesRemoved = libraryItem.media.metadata.series.filter((se) => !seriesIdsInUpdate.includes(se.id))
|
const seriesRemoved = libraryItem.media.metadata.series.filter((se) => !seriesIdsInUpdate.includes(se.id))
|
||||||
|
seriesIdsRemoved.push(...seriesRemoved.map((se) => se.id))
|
||||||
|
}
|
||||||
|
if (Array.isArray(mediaPayload.metadata?.authors)) {
|
||||||
|
const authorIdsInUpdate = mediaPayload.metadata.authors.map((au) => au.id)
|
||||||
|
const authorsRemoved = libraryItem.media.metadata.authors.filter((au) => !authorIdsInUpdate.includes(au.id))
|
||||||
|
authorIdsRemoved.push(...authorsRemoved.map((au) => au.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryItem.media.update(mediaPayload)) {
|
if (libraryItem.media.update(mediaPayload)) {
|
||||||
Logger.debug(`[LibraryItemController] Updated library item media ${libraryItem.media.metadata.title}`)
|
Logger.debug(`[LibraryItemController] Updated library item media ${libraryItem.media.metadata.title}`)
|
||||||
|
|
||||||
if (seriesRemoved.length) {
|
|
||||||
// Check remove empty series
|
|
||||||
Logger.debug(`[LibraryItemController] Series was removed from book. Check if series is now empty.`)
|
|
||||||
await this.checkRemoveEmptySeries(
|
|
||||||
libraryItem.media.id,
|
|
||||||
seriesRemoved.map((se) => se.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
await Database.updateLibraryItem(libraryItem)
|
await Database.updateLibraryItem(libraryItem)
|
||||||
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
|
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
|
||||||
itemsUpdated++
|
itemsUpdated++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seriesIdsRemoved.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIdsRemoved)
|
||||||
|
}
|
||||||
|
if (authorIdsRemoved.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIdsRemoved)
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
updates: itemsUpdated
|
updates: itemsUpdated
|
||||||
@@ -845,7 +907,13 @@ class LibraryItemController {
|
|||||||
res.setHeader('Content-Type', audioMimeType)
|
res.setHeader('Content-Type', audioMimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.download(libraryFile.metadata.path, libraryFile.metadata.filename)
|
try {
|
||||||
|
await new Promise((resolve, reject) => res.download(libraryFile.metadata.path, libraryFile.metadata.filename, (error) => (error ? reject(error) : resolve())))
|
||||||
|
Logger.info(`[LibraryItemController] Downloaded file "${libraryFile.metadata.path}"`)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(`[LibraryItemController] Failed to download file "${libraryFile.metadata.path}"`, error)
|
||||||
|
LibraryItemController.handleDownloadError(error, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -883,7 +951,13 @@ class LibraryItemController {
|
|||||||
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
|
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
|
||||||
}
|
}
|
||||||
|
|
||||||
res.sendFile(ebookFilePath)
|
try {
|
||||||
|
await new Promise((resolve, reject) => res.sendFile(ebookFilePath, (error) => (error ? reject(error) : resolve())))
|
||||||
|
Logger.info(`[LibraryItemController] Downloaded ebook file "${ebookFilePath}"`)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(`[LibraryItemController] Failed to download ebook file "${ebookFilePath}"`, error)
|
||||||
|
LibraryItemController.handleDownloadError(error, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -394,6 +394,58 @@ class MeController {
|
|||||||
res.json(req.user.toOldJSONForBrowser())
|
res.json(req.user.toOldJSONForBrowser())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST: /api/me/ereader-devices
|
||||||
|
*
|
||||||
|
* @param {RequestWithUser} req
|
||||||
|
* @param {Response} res
|
||||||
|
*/
|
||||||
|
async updateUserEReaderDevices(req, res) {
|
||||||
|
if (!req.body.ereaderDevices || !Array.isArray(req.body.ereaderDevices)) {
|
||||||
|
return res.status(400).send('Invalid payload. ereaderDevices array required')
|
||||||
|
}
|
||||||
|
|
||||||
|
const userEReaderDevices = req.body.ereaderDevices
|
||||||
|
for (const device of userEReaderDevices) {
|
||||||
|
if (!device.name || !device.email) {
|
||||||
|
return res.status(400).send('Invalid payload. ereaderDevices array items must have name and email')
|
||||||
|
} else if (device.availabilityOption !== 'specificUsers' || device.users?.length !== 1 || device.users[0] !== req.user.id) {
|
||||||
|
return res.status(400).send('Invalid payload. ereaderDevices array items must have availabilityOption "specificUsers" and only the current user')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherDevices = Database.emailSettings.ereaderDevices.filter((device) => {
|
||||||
|
return !Database.emailSettings.checkUserCanAccessDevice(device, req.user) || device.users?.length !== 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const ereaderDevices = otherDevices.concat(userEReaderDevices)
|
||||||
|
|
||||||
|
// Check for duplicate names
|
||||||
|
const nameSet = new Set()
|
||||||
|
const hasDupes = ereaderDevices.some((device) => {
|
||||||
|
if (nameSet.has(device.name)) {
|
||||||
|
return true // Duplicate found
|
||||||
|
}
|
||||||
|
nameSet.add(device.name)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasDupes) {
|
||||||
|
return res.status(400).send('Invalid payload. Duplicate "name" field found.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = Database.emailSettings.update({ ereaderDevices })
|
||||||
|
if (updated) {
|
||||||
|
await Database.updateSetting(Database.emailSettings)
|
||||||
|
SocketAuthority.clientEmitter(req.user.id, 'ereader-devices-updated', {
|
||||||
|
ereaderDevices: Database.emailSettings.ereaderDevices
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
ereaderDevices: Database.emailSettings.getEReaderDevices(req.user)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET: /api/me/stats/year/:year
|
* GET: /api/me/stats/year/:year
|
||||||
*
|
*
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user