mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-06-04 01:40:40 +02:00
Compare commits
368 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69d1744496 | |||
| 0357dc90d4 | |||
| 6cd874dffc | |||
| 6467a92de6 | |||
| 63466ec48b | |||
| de7296eaab | |||
| c251f1899d | |||
| d205c6f734 | |||
| 5e8678f1cc | |||
| 12c6f2e9a5 | |||
| 5cd14108f9 | |||
| eb853d9f09 | |||
| 4787e7fdb5 | |||
| dd0ebdf2d8 | |||
| de8b0abc3a | |||
| 08bbe1ba02 | |||
| 87bac1e33b | |||
| e9eeab6fb5 | |||
| 235d05eff3 | |||
| f9f8c6d751 | |||
| e175a9c533 | |||
| f9130a138e | |||
| ed17dd9b51 | |||
| eb505a0be7 | |||
| f3918a47e1 | |||
| c8a05920dd | |||
| e7f7d1a573 | |||
| 5201625d38 | |||
| 8c4d0c503b | |||
| d3bda898d4 | |||
| 86809dcc62 | |||
| 9fa00a1904 | |||
| 46247ecf78 | |||
| 0444829a9f | |||
| 754c121168 | |||
| 1c2ee09f18 | |||
| ee310d967e | |||
| 25b7f005c6 | |||
| 777c59458d | |||
| 9785bc02ea | |||
| 6780ef9b37 | |||
| 88a0e75576 | |||
| 476933a144 | |||
| 2464aac2bf | |||
| b6b786e3a6 | |||
| bacb8aeac7 | |||
| ba9277cc44 | |||
| 3cc5fae586 | |||
| da7d9c10ad | |||
| aa82439125 | |||
| 2e0156d9fa | |||
| 20e0172fa3 | |||
| 6928f6eeb6 | |||
| 4cdc2a8c28 | |||
| e0c674d9a9 | |||
| d7830f4bfc | |||
| 727310ab75 | |||
| f46b5a533c | |||
| f3e9cfbe45 | |||
| 4d8501c347 | |||
| b4e8f16174 | |||
| 7073f17cca | |||
| e1c41e4e58 | |||
| 13f73cc79d | |||
| d811ec3806 | |||
| e8505cb637 | |||
| 94fdd99ab5 | |||
| 331c7c011c | |||
| 5fa263023f | |||
| 7eb315a371 | |||
| 780c0dcb99 | |||
| 004210ee02 | |||
| 921880445a | |||
| 0099ae633a | |||
| 91d99deba1 | |||
| e21cbc9ff4 | |||
| 600c1e4668 | |||
| aea2951b89 | |||
| 71b943f434 | |||
| ed0484a8e1 | |||
| 5302f3225b | |||
| a94a7b7940 | |||
| 4318f64d60 | |||
| 26a6618e8f | |||
| c242e9d3d6 | |||
| 4ecb22f70d | |||
| 547a49e95b | |||
| b6875af148 | |||
| c652b5bf74 | |||
| eb0b92a547 | |||
| b56bcbb802 | |||
| 3b8af95211 | |||
| a3332f0478 | |||
| 46421d5f2c | |||
| 7db28d0e98 | |||
| 31d26929af | |||
| 086da5f6a1 | |||
| 09421a44e2 | |||
| fde51da479 | |||
| f3536dc3a3 | |||
| a0c93e5dec | |||
| 63aa6aa950 | |||
| 680099cab4 | |||
| 66f3f3eddf | |||
| a400c149a6 | |||
| 244b5ab36d | |||
| f26747627e | |||
| f57a07c483 | |||
| 080b879d8a | |||
| 63b3f22504 | |||
| 91f17efd5f | |||
| 858d697d0f | |||
| ba55413e63 | |||
| 6cef1e3f12 | |||
| 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 | |||
| 61729881cb | |||
| 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 | |||
| 27c9381e1d | |||
| 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 | |||
| 0812e189f7 | |||
| 588def6d33 | |||
| 0c244cbf95 | |||
| 7ef14aabed | |||
| 978c2b05f2 | |||
| 68fd1d67cb | |||
| bf8407274e | |||
| 3bc2941445 | |||
| 654b1d6b34 | |||
| 7a49681dd2 | |||
| 7a1623e6a1 | |||
| c25acb41fa | |||
| 4224b8a486 | |||
| 9e990d7927 | |||
| 431ae97593 | |||
| 633ff810cf | |||
| f3d2b781ab | |||
| a0b3960ee4 | |||
| e55db0afdc | |||
| ae9efe6359 | |||
| 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:
|
||||
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:
|
||||
# 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:
|
||||
- cron: '16 5 * * 4'
|
||||
|
||||
@@ -21,45 +35,44 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
language: ['javascript']
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin 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
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# 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.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# 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.
|
||||
# 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
|
||||
# queries: security-extended,security-and-quality
|
||||
# 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
|
||||
|
||||
# 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).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# 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.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
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:
|
||||
branches-ignore:
|
||||
- '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:
|
||||
build:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
/podcasts/
|
||||
/media/
|
||||
/metadata/
|
||||
/plugins/
|
||||
/client/.nuxt/
|
||||
/client/dist/
|
||||
/dist/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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">
|
||||
<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" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div v-else-if="isAlternativeBookshelfView" class="w-full mb-24e">
|
||||
<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)">
|
||||
<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>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -37,18 +37,18 @@
|
||||
<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="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 class="bookshelfDividerCategorized h-6e w-full absolute top-0 left-0 right-0 z-20"></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>
|
||||
</div>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -42,8 +42,11 @@
|
||||
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p class="text-sm">{{ $strings.ButtonAdd }}</p>
|
||||
</nuxt-link>
|
||||
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/download-queue`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastDownloadQueuePage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
|
||||
<p class="text-sm">{{ $strings.ButtonDownloadQueue }}</p>
|
||||
</nuxt-link>
|
||||
</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 -->
|
||||
<template v-if="selectedSeries">
|
||||
<p class="pl-2 text-base md:text-lg">
|
||||
@@ -265,6 +268,9 @@ export default {
|
||||
isPodcastLatestPage() {
|
||||
return this.$route.name === 'library-library-podcast-latest'
|
||||
},
|
||||
isPodcastDownloadQueuePage() {
|
||||
return this.$route.name === 'library-library-podcast-download-queue'
|
||||
},
|
||||
isAuthorsPage() {
|
||||
return this.page === 'authors'
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<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="toolbar" aria-orientation="vertical" aria-label="Config Sidebar">
|
||||
<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">
|
||||
<span class="material-symbols text-2xl">arrow_back</span>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<p class="text-xs text-gray-300 italic">{{ Source }}</p>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
<div id="bookshelf" ref="bookshelf" class="w-full overflow-y-auto" :style="{ fontSize: sizeMultiplier + 'rem' }">
|
||||
<template v-for="shelf in totalShelves">
|
||||
<div :key="shelf" :id="`shelf-${shelf - 1}`" class="w-full px-4e sm:px-8e relative" :class="{ bookshelfRow: !isAlternativeBookshelfView }" :style="{ height: shelfHeight + 'px' }">
|
||||
<!-- Card skeletons -->
|
||||
<template v-for="entityIndex in entitiesInShelf(shelf)">
|
||||
<div :key="entityIndex" class="w-full h-full absolute rounded z-5 top-0 left-0 bg-primary box-shadow-book" :style="{ transform: entityTransform(entityIndex), width: cardWidth + 'px', height: coverHeight + 'px' }" />
|
||||
</template>
|
||||
<div v-if="!isAlternativeBookshelfView" class="bookshelfDivider w-full absolute bottom-0 left-0 right-0 z-20 h-6e" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -65,7 +69,13 @@ export default {
|
||||
tempIsScanning: false,
|
||||
cardWidth: 0,
|
||||
cardHeight: 0,
|
||||
resizeObserver: null
|
||||
coverHeight: 0,
|
||||
resizeObserver: null,
|
||||
lastScrollTop: 0,
|
||||
lastTimestamp: 0,
|
||||
postScrollTimeout: null,
|
||||
currFirstEntityIndex: -1,
|
||||
currLastEntityIndex: -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -171,9 +181,6 @@ export default {
|
||||
bookWidth() {
|
||||
return this.cardWidth
|
||||
},
|
||||
bookHeight() {
|
||||
return this.cardHeight
|
||||
},
|
||||
shelfPadding() {
|
||||
if (this.bookshelfWidth < 640) return 32 * this.sizeMultiplier
|
||||
return 64 * this.sizeMultiplier
|
||||
@@ -184,9 +191,6 @@ export default {
|
||||
entityWidth() {
|
||||
return this.cardWidth
|
||||
},
|
||||
entityHeight() {
|
||||
return this.cardHeight
|
||||
},
|
||||
shelfPaddingHeight() {
|
||||
return 16
|
||||
},
|
||||
@@ -354,50 +358,53 @@ export default {
|
||||
}
|
||||
},
|
||||
loadPage(page) {
|
||||
this.pagesLoaded[page] = true
|
||||
this.fetchEntites(page)
|
||||
if (!this.pagesLoaded[page]) this.pagesLoaded[page] = this.fetchEntites(page)
|
||||
return this.pagesLoaded[page]
|
||||
},
|
||||
showHideBookPlaceholder(index, show) {
|
||||
var el = document.getElementById(`book-${index}-placeholder`)
|
||||
if (el) el.style.display = show ? 'flex' : 'none'
|
||||
},
|
||||
mountEntites(fromIndex, toIndex) {
|
||||
mountEntities(fromIndex, toIndex) {
|
||||
for (let i = fromIndex; i < toIndex; i++) {
|
||||
if (!this.entityIndexesMounted.includes(i)) {
|
||||
this.cardsHelpers.mountEntityCard(i)
|
||||
}
|
||||
}
|
||||
},
|
||||
handleScroll(scrollTop) {
|
||||
this.currScrollTop = scrollTop
|
||||
var firstShelfIndex = Math.floor(scrollTop / this.shelfHeight)
|
||||
var lastShelfIndex = Math.ceil((scrollTop + this.bookshelfHeight) / this.shelfHeight)
|
||||
lastShelfIndex = Math.min(this.totalShelves - 1, lastShelfIndex)
|
||||
|
||||
var firstBookIndex = firstShelfIndex * this.entitiesPerShelf
|
||||
var lastBookIndex = lastShelfIndex * this.entitiesPerShelf + this.entitiesPerShelf
|
||||
lastBookIndex = Math.min(this.totalEntities, lastBookIndex)
|
||||
|
||||
var firstBookPage = Math.floor(firstBookIndex / this.booksPerFetch)
|
||||
var lastBookPage = Math.floor(lastBookIndex / this.booksPerFetch)
|
||||
if (!this.pagesLoaded[firstBookPage]) {
|
||||
// console.log('Must load next batch', firstBookPage, 'book index', firstBookIndex)
|
||||
this.loadPage(firstBookPage)
|
||||
}
|
||||
if (!this.pagesLoaded[lastBookPage]) {
|
||||
// console.log('Must load last next batch', lastBookPage, 'book index', lastBookIndex)
|
||||
this.loadPage(lastBookPage)
|
||||
}
|
||||
|
||||
getVisibleIndices(scrollTop) {
|
||||
const firstShelfIndex = Math.floor(scrollTop / this.shelfHeight)
|
||||
const lastShelfIndex = Math.min(Math.ceil((scrollTop + this.bookshelfHeight) / this.shelfHeight), this.totalShelves - 1)
|
||||
const firstEntityIndex = firstShelfIndex * this.entitiesPerShelf
|
||||
const lastEntityIndex = Math.min(lastShelfIndex * this.entitiesPerShelf + this.entitiesPerShelf, this.totalEntities)
|
||||
return { firstEntityIndex, lastEntityIndex }
|
||||
},
|
||||
postScroll() {
|
||||
const { firstEntityIndex, lastEntityIndex } = this.getVisibleIndices(this.currScrollTop)
|
||||
this.entityIndexesMounted = this.entityIndexesMounted.filter((_index) => {
|
||||
if (_index < firstBookIndex || _index >= lastBookIndex) {
|
||||
var el = document.getElementById(`book-card-${_index}`)
|
||||
if (el) el.remove()
|
||||
if (_index < firstEntityIndex || _index >= lastEntityIndex) {
|
||||
var el = this.entityComponentRefs[_index]
|
||||
if (el && el.$el) el.$el.remove()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
this.mountEntites(firstBookIndex, lastBookIndex)
|
||||
},
|
||||
handleScroll(scrollTop) {
|
||||
this.currScrollTop = scrollTop
|
||||
const { firstEntityIndex, lastEntityIndex } = this.getVisibleIndices(scrollTop)
|
||||
if (firstEntityIndex === this.currFirstEntityIndex && lastEntityIndex === this.currLastEntityIndex) return
|
||||
this.currFirstEntityIndex = firstEntityIndex
|
||||
this.currLastEntityIndex = lastEntityIndex
|
||||
|
||||
clearTimeout(this.postScrollTimeout)
|
||||
const firstPage = Math.floor(firstEntityIndex / this.booksPerFetch)
|
||||
const lastPage = Math.floor(lastEntityIndex / this.booksPerFetch)
|
||||
Promise.all([this.loadPage(firstPage), this.loadPage(lastPage)])
|
||||
.then(() => this.mountEntities(firstEntityIndex, lastEntityIndex))
|
||||
.catch((error) => console.error('Failed to load page', error))
|
||||
|
||||
this.postScrollTimeout = setTimeout(this.postScroll, 500)
|
||||
},
|
||||
async resetEntities() {
|
||||
if (this.isFetchingEntities) {
|
||||
@@ -405,8 +412,6 @@ export default {
|
||||
return
|
||||
}
|
||||
this.destroyEntityComponents()
|
||||
this.entityIndexesMounted = []
|
||||
this.entityComponentRefs = {}
|
||||
this.pagesLoaded = {}
|
||||
this.entities = []
|
||||
this.totalShelves = 0
|
||||
@@ -416,40 +421,21 @@ export default {
|
||||
this.initialized = false
|
||||
|
||||
this.initSizeData()
|
||||
this.pagesLoaded[0] = true
|
||||
await this.fetchEntites(0)
|
||||
await this.loadPage(0)
|
||||
var lastBookIndex = Math.min(this.totalEntities, this.shelvesPerPage * this.entitiesPerShelf)
|
||||
this.mountEntites(0, lastBookIndex)
|
||||
this.mountEntities(0, lastBookIndex)
|
||||
},
|
||||
remountEntities() {
|
||||
for (const key in this.entityComponentRefs) {
|
||||
if (this.entityComponentRefs[key]) {
|
||||
this.entityComponentRefs[key].destroy()
|
||||
}
|
||||
}
|
||||
this.entityComponentRefs = {}
|
||||
this.entityIndexesMounted.forEach((i) => {
|
||||
this.cardsHelpers.mountEntityCard(i)
|
||||
})
|
||||
},
|
||||
rebuild() {
|
||||
async rebuild() {
|
||||
this.initSizeData()
|
||||
|
||||
var lastBookIndex = Math.min(this.totalEntities, this.booksPerFetch)
|
||||
this.entityIndexesMounted = []
|
||||
for (let i = 0; i < lastBookIndex; i++) {
|
||||
this.entityIndexesMounted.push(i)
|
||||
if (!this.entities[i]) {
|
||||
const page = Math.floor(i / this.booksPerFetch)
|
||||
this.loadPage(page)
|
||||
}
|
||||
}
|
||||
this.destroyEntityComponents()
|
||||
await this.loadPage(0)
|
||||
var bookshelfEl = document.getElementById('bookshelf')
|
||||
if (bookshelfEl) {
|
||||
bookshelfEl.scrollTop = 0
|
||||
}
|
||||
|
||||
this.$nextTick(this.remountEntities)
|
||||
this.mountEntities(0, lastBookIndex)
|
||||
},
|
||||
buildSearchParams() {
|
||||
if (this.page === 'search' || this.page === 'collections') {
|
||||
@@ -513,12 +499,29 @@ export default {
|
||||
if (wasUpdated) {
|
||||
this.resetEntities()
|
||||
} else if (settings.bookshelfCoverSize !== this.currentBookWidth) {
|
||||
this.executeRebuild()
|
||||
this.rebuild()
|
||||
}
|
||||
},
|
||||
getScrollRate() {
|
||||
const currentTimestamp = Date.now()
|
||||
const timeDelta = currentTimestamp - this.lastTimestamp
|
||||
const scrollDelta = this.currScrollTop - this.lastScrollTop
|
||||
const scrollRate = Math.abs(scrollDelta) / (timeDelta || 1)
|
||||
this.lastScrollTop = this.currScrollTop
|
||||
this.lastTimestamp = currentTimestamp
|
||||
return scrollRate
|
||||
},
|
||||
scroll(e) {
|
||||
if (!e || !e.target) return
|
||||
var { scrollTop } = e.target
|
||||
clearTimeout(this.scrollTimeout)
|
||||
const { scrollTop } = e.target
|
||||
const scrollRate = this.getScrollRate()
|
||||
if (scrollRate > 5) {
|
||||
this.scrollTimeout = setTimeout(() => {
|
||||
this.handleScroll(scrollTop)
|
||||
}, 25)
|
||||
return
|
||||
}
|
||||
this.handleScroll(scrollTop)
|
||||
},
|
||||
libraryItemAdded(libraryItem) {
|
||||
@@ -667,13 +670,14 @@ export default {
|
||||
},
|
||||
updatePagesLoaded() {
|
||||
let numPages = Math.ceil(this.totalEntities / this.booksPerFetch)
|
||||
this.pagesLoaded = {}
|
||||
for (let page = 0; page < numPages; page++) {
|
||||
let numEntities = Math.min(this.totalEntities - page * this.booksPerFetch, this.booksPerFetch)
|
||||
this.pagesLoaded[page] = true
|
||||
this.pagesLoaded[page] = Promise.resolve()
|
||||
for (let i = 0; i < numEntities; i++) {
|
||||
const index = page * this.booksPerFetch + i
|
||||
if (!this.entities[index]) {
|
||||
this.pagesLoaded[page] = false
|
||||
if (this.pagesLoaded[page]) delete this.pagesLoaded[page]
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -688,7 +692,6 @@ export default {
|
||||
var entitiesPerShelfBefore = this.entitiesPerShelf
|
||||
|
||||
var { clientHeight, clientWidth } = bookshelf
|
||||
// console.log('Init bookshelf width', clientWidth, 'window width', window.innerWidth)
|
||||
this.mountWindowWidth = window.innerWidth
|
||||
this.bookshelfHeight = clientHeight
|
||||
this.bookshelfWidth = clientWidth
|
||||
@@ -713,10 +716,9 @@ export default {
|
||||
this.initSizeData(bookshelf)
|
||||
this.checkUpdateSearchParams()
|
||||
|
||||
this.pagesLoaded[0] = true
|
||||
await this.fetchEntites(0)
|
||||
await this.loadPage(0)
|
||||
var lastBookIndex = Math.min(this.totalEntities, this.shelvesPerPage * this.entitiesPerShelf)
|
||||
this.mountEntites(0, lastBookIndex)
|
||||
this.mountEntities(0, lastBookIndex)
|
||||
|
||||
// Set last scroll position for this bookshelf page
|
||||
if (this.$store.state.lastBookshelfScrollData[this.page] && window.bookshelf) {
|
||||
@@ -747,7 +749,7 @@ export default {
|
||||
var bookshelf = document.getElementById('bookshelf')
|
||||
if (bookshelf) {
|
||||
this.init(bookshelf)
|
||||
bookshelf.addEventListener('scroll', this.scroll)
|
||||
bookshelf.addEventListener('scroll', this.scroll, { passive: true })
|
||||
}
|
||||
})
|
||||
|
||||
@@ -810,10 +812,14 @@ export default {
|
||||
},
|
||||
destroyEntityComponents() {
|
||||
for (const key in this.entityComponentRefs) {
|
||||
if (this.entityComponentRefs[key] && this.entityComponentRefs[key].destroy) {
|
||||
this.entityComponentRefs[key].destroy()
|
||||
const ref = this.entityComponentRefs[key]
|
||||
if (ref && ref.destroy) {
|
||||
if (ref.$el) ref.$el.remove()
|
||||
ref.destroy()
|
||||
}
|
||||
}
|
||||
this.entityComponentRefs = {}
|
||||
this.entityIndexesMounted = []
|
||||
},
|
||||
scan() {
|
||||
this.tempIsScanning = true
|
||||
@@ -826,6 +832,14 @@ export default {
|
||||
.finally(() => {
|
||||
this.tempIsScanning = false
|
||||
})
|
||||
},
|
||||
entitiesInShelf(shelf) {
|
||||
return shelf == this.totalShelves ? this.totalEntities % this.entitiesPerShelf || this.entitiesPerShelf : this.entitiesPerShelf
|
||||
},
|
||||
entityTransform(entityIndex) {
|
||||
const shelfOffsetY = this.shelfPaddingHeight * this.sizeMultiplier
|
||||
const shelfOffsetX = (entityIndex - 1) * this.totalEntityCardWidth + this.bookshelfMarginLeft
|
||||
return `translate3d(${shelfOffsetX}px, ${shelfOffsetY}px, 0px)`
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
@showBookmarks="showBookmarks"
|
||||
@showSleepTimer="showSleepTimerModal = true"
|
||||
@showPlayerQueueItems="showPlayerQueueItemsModal = true"
|
||||
@showPlayerSettings="showPlayerSettingsModal = true"
|
||||
/>
|
||||
|
||||
<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-player-queue-items-modal v-model="showPlayerQueueItemsModal" />
|
||||
|
||||
<modals-player-settings-modal v-model="showPlayerSettingsModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -81,7 +78,6 @@ export default {
|
||||
currentTime: 0,
|
||||
showSleepTimerModal: false,
|
||||
showPlayerQueueItemsModal: false,
|
||||
showPlayerSettingsModal: false,
|
||||
sleepTimerSet: false,
|
||||
sleepTimerRemaining: 0,
|
||||
sleepTimerType: null,
|
||||
@@ -378,19 +374,27 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API
|
||||
if ('mediaSession' in navigator) {
|
||||
var coverImageSrc = this.$store.getters['globals/getLibraryItemCoverSrc'](this.streamLibraryItem, '/Logo.png', true)
|
||||
const artwork = [
|
||||
{
|
||||
src: coverImageSrc
|
||||
}
|
||||
]
|
||||
const chapterInfo = []
|
||||
if (this.chapters.length) {
|
||||
this.chapters.forEach((chapter) => {
|
||||
chapterInfo.push({
|
||||
title: chapter.title,
|
||||
startTime: chapter.start
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: this.title,
|
||||
artist: this.playerHandler.displayAuthor || this.mediaMetadata.authorName || 'Unknown',
|
||||
album: this.mediaMetadata.seriesName || '',
|
||||
artwork
|
||||
artwork: [
|
||||
{
|
||||
src: this.$store.getters['globals/getLibraryItemCoverSrc'](this.streamLibraryItem, '/Logo.png', true)
|
||||
}
|
||||
]
|
||||
})
|
||||
console.log('Set media session metadata', navigator.mediaSession.metadata)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<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 -->
|
||||
<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'">
|
||||
<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" />
|
||||
|
||||
@@ -68,6 +68,9 @@ export default {
|
||||
cardHeight() {
|
||||
return this.height * this.sizeMultiplier
|
||||
},
|
||||
coverHeight() {
|
||||
return this.cardHeight
|
||||
},
|
||||
userToken() {
|
||||
return this.store.getters['user/getToken']
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
<div ref="card" :id="`book-card-${index}`" tabindex="0" :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 ' }">
|
||||
<!-- 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">
|
||||
@@ -14,21 +14,21 @@
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- 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-if="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 -->
|
||||
<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>
|
||||
<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 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 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 -->
|
||||
<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>
|
||||
<!-- 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' }">
|
||||
<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>
|
||||
|
||||
<!-- Series sequence -->
|
||||
@@ -114,7 +114,7 @@
|
||||
|
||||
<!-- 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' }">
|
||||
<p :style="{ fontSize: 0.8 + 'em' }">{{ numEpisodes }}</p>
|
||||
<p :style="{ fontSize: 0.8 + 'em' }" role="status" :aria-label="$strings.LabelNumberOfEpisodes">{{ numEpisodes }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Podcast Num Episodes -->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
||||
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
|
||||
<div class="w-full h-full bg-primary relative rounded overflow-hidden">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
<div cy-id="card" ref="card" :id="`series-card-${index}`" tabindex="0" :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 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">
|
||||
@@ -7,12 +7,12 @@
|
||||
</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">
|
||||
<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 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>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<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" />
|
||||
</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-else class="material-symbols" style="font-size: 1.2rem">close</span>
|
||||
</div>
|
||||
</button>
|
||||
</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">
|
||||
<li v-if="isTyping" class="py-2 px-2">
|
||||
<p>{{ $strings.MessageThinking }}</p>
|
||||
@@ -157,7 +157,7 @@ export default {
|
||||
clearTimeout(this.focusTimeout)
|
||||
this.focusTimeout = setTimeout(() => {
|
||||
this.showMenu = false
|
||||
}, 200)
|
||||
}, 100)
|
||||
},
|
||||
async runSearch(value) {
|
||||
this.lastSearch = value
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
<template>
|
||||
<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">
|
||||
<span class="flex items-center justify-between">
|
||||
<span class="block truncate text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
||||
</span>
|
||||
<div class="relative h-7">
|
||||
<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="flex items-center justify-between">
|
||||
<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">
|
||||
<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" />
|
||||
</svg>
|
||||
</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>
|
||||
</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">
|
||||
<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">
|
||||
<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">
|
||||
<span class="font-normal ml-3 block truncate text-sm">{{ item.text }}</span>
|
||||
</div>
|
||||
<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>
|
||||
<!-- selected checkmark icon -->
|
||||
<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>
|
||||
</template>
|
||||
</ul>
|
||||
<ul v-show="sublist" class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
||||
<li class="text-gray-50 select-none relative py-2 pl-9 cursor-pointer hover:bg-white/5" role="option" @click="sublist = null">
|
||||
<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="menuitem" @click="sublist = null">
|
||||
<div class="absolute left-1 top-0 bottom-0 h-full flex items-center">
|
||||
<span class="material-symbols text-2xl">arrow_left</span>
|
||||
</div>
|
||||
@@ -40,13 +42,13 @@
|
||||
<span class="font-normal block truncate">{{ $strings.ButtonBack }}</span>
|
||||
</div>
|
||||
</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">
|
||||
<span class="font-normal block truncate py-2">{{ $getString('LabelLibraryFilterSublistEmpty', [selectedSublistText]) }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<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">
|
||||
<span class="font-normal truncate py-2 text-xs">{{ item.text }}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<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="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>
|
||||
</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">
|
||||
<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">
|
||||
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
||||
</div>
|
||||
<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>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<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="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>
|
||||
</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">
|
||||
<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">
|
||||
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
|
||||
</div>
|
||||
<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>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
},
|
||||
imgSrc() {
|
||||
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: {
|
||||
|
||||
@@ -121,6 +121,8 @@ export default {
|
||||
|
||||
var img = document.createElement('img')
|
||||
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.style.objectFit = showCoverBg ? 'contain' : 'cover'
|
||||
|
||||
|
||||
@@ -69,6 +69,15 @@
|
||||
</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="w-1/2">
|
||||
<p id="explicit-content-permissions-toggle">{{ $strings.LabelPermissionsAccessExplicitContent }}</p>
|
||||
@@ -354,7 +363,8 @@ export default {
|
||||
accessExplicitContent: type === 'admin',
|
||||
accessAllLibraries: true,
|
||||
accessAllTags: true,
|
||||
selectedTagsNotAccessible: false
|
||||
selectedTagsNotAccessible: false,
|
||||
createEreader: type === 'admin'
|
||||
}
|
||||
},
|
||||
init() {
|
||||
@@ -387,7 +397,8 @@ export default {
|
||||
accessAllLibraries: true,
|
||||
accessAllTags: true,
|
||||
accessExplicitContent: false,
|
||||
selectedTagsNotAccessible: false
|
||||
selectedTagsNotAccessible: false,
|
||||
createEreader: false
|
||||
},
|
||||
librariesAccessible: [],
|
||||
itemTagsSelected: []
|
||||
|
||||
@@ -54,8 +54,7 @@ export default {
|
||||
options: {
|
||||
provider: undefined,
|
||||
overrideDetails: true,
|
||||
overrideCover: true,
|
||||
overrideDefaults: true
|
||||
overrideCover: true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -99,8 +98,8 @@ export default {
|
||||
init() {
|
||||
// If we don't have a set provider (first open of dialog) or we've switched library, set
|
||||
// the selected provider to the current library default provider
|
||||
if (!this.options.provider || this.options.lastUsedLibrary != this.currentLibraryId) {
|
||||
this.options.lastUsedLibrary = this.currentLibraryId
|
||||
if (!this.options.provider || this.lastUsedLibrary != this.currentLibraryId) {
|
||||
this.lastUsedLibrary = this.currentLibraryId
|
||||
this.options.provider = this.libraryProvider
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div ref="wrapper" class="hidden absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 rounded-lg items-center justify-center" style="z-index: 61" @click="clickClose">
|
||||
<div class="absolute top-3 right-3 md:top-5 md:right-5 h-8 w-8 md:h-12 md:w-12 flex items-center justify-center cursor-pointer text-white hover:text-gray-300">
|
||||
<div ref="wrapper" role="dialog" aria-modal="true" class="hidden absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 rounded-lg items-center justify-center" style="z-index: 61" @click="clickClose">
|
||||
<button type="button" class="absolute top-3 right-3 md:top-5 md:right-5 h-8 w-8 md:h-12 md:w-12 flex items-center justify-center cursor-pointer text-white hover:text-gray-300" aria-label="Close modal">
|
||||
<span class="material-symbols text-2xl md:text-4xl">close</span>
|
||||
</div>
|
||||
</button>
|
||||
<div ref="content" class="text-white">
|
||||
<form v-if="selectedSeries" @submit.prevent="submitSeriesForm">
|
||||
<div class="bg-bg rounded-lg px-2 py-6 sm:p-6 md:p-8" @click.stop>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<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" />
|
||||
|
||||
<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>
|
||||
</button>
|
||||
<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 />
|
||||
<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 />
|
||||
@@ -126,6 +126,9 @@ export default {
|
||||
|
||||
this.$eventBus.$on('modal-hotkey', this.hotkey)
|
||||
this.$store.commit('setOpenModal', this.name)
|
||||
|
||||
// Set focus to the modal content
|
||||
this.content.focus()
|
||||
},
|
||||
setHide() {
|
||||
if (this.content) this.content.style.transform = 'scale(0)'
|
||||
|
||||
@@ -59,12 +59,19 @@ export default {
|
||||
setJumpBackwardAmount(val) {
|
||||
this.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() {
|
||||
this.useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack')
|
||||
this.jumpForwardAmount = this.$store.getters['user/getUserSetting']('jumpForwardAmount')
|
||||
this.jumpBackwardAmount = this.$store.getters['user/getUserSetting']('jumpBackwardAmount')
|
||||
this.settingsUpdated()
|
||||
this.$eventBus.$on('user-settings', this.settingsUpdated)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$eventBus.$off('user-settings', this.settingsUpdated)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -19,12 +19,13 @@
|
||||
<ui-text-input v-model="currentShareUrl" show-copy readonly class="text-base h-10" />
|
||||
</div>
|
||||
<div class="w-full py-2 px-1">
|
||||
<p v-if="currentShare.expiresAt" class="text-base">{{ $getString('MessageShareExpiresIn', [currentShareTimeRemaining]) }}</p>
|
||||
<p v-if="currentShare.isDownloadable" class="text-sm mb-2">{{ $strings.LabelDownloadable }}</p>
|
||||
<p v-if="currentShare.expiresAt">{{ $getString('MessageShareExpiresIn', [currentShareTimeRemaining]) }}</p>
|
||||
<p v-else>{{ $strings.LabelPermanent }}</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between space-y-4 sm:space-y-0 sm:space-x-4 mb-4">
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between space-y-4 sm:space-y-0 sm:space-x-4 mb-2">
|
||||
<div class="w-full sm:w-48">
|
||||
<label class="px-1 text-sm font-semibold block">{{ $strings.LabelSlug }}</label>
|
||||
<ui-text-input v-model="newShareSlug" class="text-base h-10" />
|
||||
@@ -46,6 +47,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center w-full md:w-1/2 mb-4">
|
||||
<p class="text-sm text-gray-300 py-1 px-1">{{ $strings.LabelDownloadable }}</p>
|
||||
<ui-toggle-switch size="sm" v-model="isDownloadable" />
|
||||
<ui-tooltip :text="$strings.LabelShareDownloadableHelp">
|
||||
<p class="pl-4 text-sm">
|
||||
<span class="material-symbols icon-text text-sm">info</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<p class="text-sm text-gray-300 py-1 px-1" v-html="$getString('MessageShareURLWillBe', [demoShareUrl])" />
|
||||
<p class="text-sm text-gray-300 py-1 px-1" v-html="$getString('MessageShareExpirationWillBe', [expirationDateString])" />
|
||||
</template>
|
||||
@@ -81,7 +91,8 @@ export default {
|
||||
text: this.$strings.LabelDays,
|
||||
value: 'days'
|
||||
}
|
||||
]
|
||||
],
|
||||
isDownloadable: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -172,7 +183,8 @@ export default {
|
||||
slug: this.newShareSlug,
|
||||
mediaItemType: 'book',
|
||||
mediaItemId: this.libraryItem.media.id,
|
||||
expiresAt: this.expireDurationSeconds ? Date.now() + this.expireDurationSeconds * 1000 : 0
|
||||
expiresAt: this.expireDurationSeconds ? Date.now() + this.expireDurationSeconds * 1000 : 0,
|
||||
isDownloadable: this.isDownloadable
|
||||
}
|
||||
this.processing = true
|
||||
this.$axios
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<modals-modal v-model="show" name="changelog" :width="800" :height="'unset'">
|
||||
<template #outer>
|
||||
<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>
|
||||
</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">
|
||||
@@ -13,7 +13,7 @@
|
||||
</p>
|
||||
<div class="custom-text" v-html="getChangelog(release)" />
|
||||
</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>
|
||||
</div>
|
||||
</modals-modal>
|
||||
|
||||
@@ -138,7 +138,6 @@ export default {
|
||||
.$post(`/api/collections/${collection.id}/batch/remove`, { books: this.selectedBookIds })
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Books removed from collection`, updatedCollection)
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsRemoveSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -152,7 +151,6 @@ export default {
|
||||
.$delete(`/api/collections/${collection.id}/book/${this.selectedLibraryItemId}`)
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Book removed from collection`, updatedCollection)
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsRemoveSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -167,12 +165,11 @@ export default {
|
||||
this.processing = true
|
||||
|
||||
if (this.showBatchCollectionModal) {
|
||||
// BATCH Remove books
|
||||
// BATCH Add books
|
||||
this.$axios
|
||||
.$post(`/api/collections/${collection.id}/batch/add`, { books: this.selectedBookIds })
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Books added to collection`, updatedCollection)
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsAddSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -187,7 +184,6 @@ export default {
|
||||
.$post(`/api/collections/${collection.id}/book`, { id: this.selectedLibraryItemId })
|
||||
.then((updatedCollection) => {
|
||||
console.log(`Book added to collection`, updatedCollection)
|
||||
this.$toast.success(this.$strings.ToastCollectionItemsAddSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -214,7 +210,6 @@ export default {
|
||||
.$post('/api/collections', newCollection)
|
||||
.then((data) => {
|
||||
console.log('New Collection Created', data)
|
||||
this.$toast.success(`Collection "${data.name}" created`)
|
||||
this.processing = false
|
||||
this.newCollectionName = ''
|
||||
})
|
||||
|
||||
@@ -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>
|
||||
@@ -2,24 +2,24 @@
|
||||
<modals-modal v-model="show" name="edit-book" :width="800" :height="height" :processing="processing" :content-margin-top="marginTop">
|
||||
<template #outer>
|
||||
<div class="absolute top-0 left-0 p-4 landscape:px-4 landscape:py-2 md:portrait:p-5 lg:p-5 w-2/3 overflow-hidden pointer-events-none">
|
||||
<p class="text-xl md:portrait:text-3xl md:landscape:text-lg lg:text-3xl text-white truncate pointer-events-none">{{ title }}</p>
|
||||
<h1 class="text-xl md:portrait:text-3xl md:landscape:text-lg lg:text-3xl text-white truncate pointer-events-none">{{ title }}</h1>
|
||||
</div>
|
||||
</template>
|
||||
<div class="absolute -top-10 left-0 z-10 w-full flex">
|
||||
<div role="tablist" class="absolute -top-10 left-0 z-10 w-full flex">
|
||||
<template v-for="tab in availableTabs">
|
||||
<div :key="tab.id" class="w-28 rounded-t-lg flex items-center justify-center mr-0.5 sm:mr-1 cursor-pointer hover:bg-bg border-t border-l border-r border-black-300 tab text-xs sm:text-base" :class="selectedTab === tab.id ? 'tab-selected bg-bg pb-px' : 'bg-primary text-gray-400'" @click="selectTab(tab.id)">{{ tab.title }}</div>
|
||||
<button :key="tab.id" role="tab" class="w-28 rounded-t-lg flex items-center justify-center mr-0.5 sm:mr-1 cursor-pointer hover:bg-bg border-t border-l border-r border-black-300 tab text-xs sm:text-base" :class="selectedTab === tab.id ? 'tab-selected bg-bg pb-px' : 'bg-primary text-gray-400'" @click="selectTab(tab.id)">{{ tab.title }}</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-show="canGoPrev" class="absolute -left-24 top-0 bottom-0 h-full pointer-events-none flex items-center px-6">
|
||||
<div class="material-symbols text-5xl text-white text-opacity-50 hover:text-opacity-90 cursor-pointer pointer-events-auto" @click.stop.prevent="goPrevBook" @mousedown.prevent>arrow_back_ios</div>
|
||||
</div>
|
||||
<div v-show="canGoNext" class="absolute -right-24 top-0 bottom-0 h-full pointer-events-none flex items-center px-6">
|
||||
<div class="material-symbols text-5xl text-white text-opacity-50 hover:text-opacity-90 cursor-pointer pointer-events-auto" @click.stop.prevent="goNextBook" @mousedown.prevent>arrow_forward_ios</div>
|
||||
<div role="tabpanel" class="w-full h-full max-h-full text-sm rounded-b-lg rounded-tr-lg bg-bg shadow-lg border border-black-300 relative">
|
||||
<component v-if="libraryItem && show" :is="tabName" :library-item="libraryItem" :processing.sync="processing" @close="show = false" @selectTab="selectTab" />
|
||||
</div>
|
||||
|
||||
<div class="w-full h-full max-h-full text-sm rounded-b-lg rounded-tr-lg bg-bg shadow-lg border border-black-300 relative">
|
||||
<component v-if="libraryItem && show" :is="tabName" :library-item="libraryItem" :processing.sync="processing" @close="show = false" @selectTab="selectTab" />
|
||||
<div v-show="canGoPrev" class="absolute -left-24 top-0 bottom-0 h-full pointer-events-none flex items-center px-6">
|
||||
<button class="material-symbols text-5xl text-white text-opacity-50 hover:text-opacity-90 cursor-pointer pointer-events-auto" :aria-label="$strings.ButtonNext" @click.stop.prevent="goPrevBook" @mousedown.prevent>arrow_back_ios</button>
|
||||
</div>
|
||||
<div v-show="canGoNext" class="absolute -right-24 top-0 bottom-0 h-full pointer-events-none flex items-center px-6">
|
||||
<button class="material-symbols text-5xl text-white text-opacity-50 hover:text-opacity-90 cursor-pointer pointer-events-auto" :aria-label="$strings.ButtonPrevious" @click.stop.prevent="goNextBook" @mousedown.prevent>arrow_forward_ios</button>
|
||||
</div>
|
||||
</modals-modal>
|
||||
</template>
|
||||
|
||||
@@ -111,7 +111,6 @@ export default {
|
||||
},
|
||||
updateLibrary(library) {
|
||||
this.mapLibraryToCopy(library)
|
||||
console.log('Updated library', this.libraryCopy)
|
||||
},
|
||||
getNewLibraryData() {
|
||||
return {
|
||||
@@ -128,7 +127,9 @@ export default {
|
||||
autoScanCronExpression: null,
|
||||
hideSingleBookSeries: 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.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
|
||||
if (!this.$store.state.libraries.currentLibraryId) {
|
||||
console.log('Setting initially library id', res.id)
|
||||
// First library added
|
||||
this.$store.dispatch('libraries/fetch', res.id)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,94 @@
|
||||
<template>
|
||||
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
|
||||
<div class="flex items-center py-3">
|
||||
<ui-toggle-switch v-model="useSquareBookCovers" @input="formUpdated" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
|
||||
<p class="pl-4 text-base">
|
||||
{{ $strings.LabelSettingsSquareBookCovers }}
|
||||
<span class="material-symbols icon-text text-sm">info</span>
|
||||
</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 }}
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex items-center p-2 w-full md:w-1/2">
|
||||
<ui-toggle-switch v-model="useSquareBookCovers" size="sm" @input="formUpdated" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
|
||||
<p class="pl-4 text-sm">
|
||||
{{ $strings.LabelSettingsSquareBookCovers }}
|
||||
<span class="material-symbols icon-text text-sm">info</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isBookLibrary" class="py-3">
|
||||
<div class="flex items-center">
|
||||
<ui-toggle-switch v-model="onlyShowLaterBooksInContinueSeries" @input="formUpdated" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp">
|
||||
<p class="pl-4 text-base">
|
||||
{{ $strings.LabelSettingsOnlyShowLaterBooksInContinueSeries }}
|
||||
<div class="p-2 w-full md:w-1/2">
|
||||
<div class="flex items-center">
|
||||
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" size="sm" @input="formUpdated" />
|
||||
<ui-toggle-switch v-else disabled size="sm" :value="false" />
|
||||
<p class="pl-4 text-sm">{{ $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 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>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isBookLibrary" class="py-3">
|
||||
<div class="flex items-center">
|
||||
<ui-toggle-switch v-model="epubsAllowScriptedContent" @input="formUpdated" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp">
|
||||
<p class="pl-4 text-base">
|
||||
{{ $strings.LabelSettingsEpubsAllowScriptedContent }}
|
||||
<span class="material-symbols icon-text text-sm">info</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
|
||||
<div class="flex items-center">
|
||||
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" size="sm" @input="formUpdated" />
|
||||
<p class="pl-4 text-sm">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</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="skipMatchingMediaWithIsbn" size="sm" @input="formUpdated" />
|
||||
<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 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>
|
||||
</template>
|
||||
@@ -97,7 +113,9 @@ export default {
|
||||
epubsAllowScriptedContent: false,
|
||||
hideSingleBookSeries: false,
|
||||
onlyShowLaterBooksInContinueSeries: false,
|
||||
podcastSearchRegion: 'us'
|
||||
podcastSearchRegion: 'us',
|
||||
markAsFinishedWhen: 'timeRemaining',
|
||||
markAsFinishedValue: 10
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -119,10 +137,34 @@ export default {
|
||||
providers() {
|
||||
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
|
||||
return this.$store.state.scanners.providers
|
||||
},
|
||||
maskAsFinishedWhenItems() {
|
||||
return [
|
||||
{
|
||||
text: this.$strings.LabelSettingsLibraryMarkAsFinishedTimeRemaining,
|
||||
value: 'timeRemaining'
|
||||
},
|
||||
{
|
||||
text: this.$strings.LabelSettingsLibraryMarkAsFinishedPercentComplete,
|
||||
value: 'percentComplete'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
markAsFinishedWhenChanged(val) {
|
||||
if (val === 'percentComplete' && this.markAsFinishedValue > 100) {
|
||||
this.markAsFinishedValue = 100
|
||||
}
|
||||
this.formUpdated()
|
||||
},
|
||||
markAsFinishedChanged(val) {
|
||||
this.formUpdated()
|
||||
},
|
||||
getLibraryData() {
|
||||
let markAsFinishedTimeRemaining = this.markAsFinishedWhen === 'timeRemaining' ? Number(this.markAsFinishedValue) : null
|
||||
let markAsFinishedPercentComplete = this.markAsFinishedWhen === 'percentComplete' ? Number(this.markAsFinishedValue) : null
|
||||
|
||||
return {
|
||||
settings: {
|
||||
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
|
||||
@@ -133,7 +175,9 @@ export default {
|
||||
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
|
||||
hideSingleBookSeries: !!this.hideSingleBookSeries,
|
||||
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.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
|
||||
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() {
|
||||
|
||||
@@ -130,7 +130,6 @@ export default {
|
||||
.$post(`/api/playlists/${playlist.id}/batch/remove`, { items: itemObjects })
|
||||
.then((updatedPlaylist) => {
|
||||
console.log(`Items removed from playlist`, updatedPlaylist)
|
||||
this.$toast.success(this.$strings.ToastPlaylistUpdateSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -148,7 +147,6 @@ export default {
|
||||
.$post(`/api/playlists/${playlist.id}/batch/add`, { items: itemObjects })
|
||||
.then((updatedPlaylist) => {
|
||||
console.log(`Items added to playlist`, updatedPlaylist)
|
||||
this.$toast.success(this.$strings.ToastPlaylistUpdateSuccess)
|
||||
this.processing = false
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -174,7 +172,6 @@ export default {
|
||||
.$post('/api/playlists', newPlaylist)
|
||||
.then((data) => {
|
||||
console.log('New playlist created', data)
|
||||
this.$toast.success(this.$strings.ToastPlaylistCreateSuccess + ': ' + data.name)
|
||||
this.processing = false
|
||||
this.newPlaylistName = ''
|
||||
})
|
||||
|
||||
@@ -170,6 +170,12 @@ export default {
|
||||
this.show = false
|
||||
}
|
||||
},
|
||||
libraryItemUpdated(libraryItem) {
|
||||
const episode = libraryItem.media.episodes.find((e) => e.id === this.selectedEpisodeId)
|
||||
if (episode) {
|
||||
this.episodeItem = episode
|
||||
}
|
||||
},
|
||||
hotkey(action) {
|
||||
if (action === this.$hotkeys.Modal.NEXT_PAGE) {
|
||||
this.goNextEpisode()
|
||||
@@ -178,9 +184,15 @@ export default {
|
||||
}
|
||||
},
|
||||
registerListeners() {
|
||||
if (this.libraryItem) {
|
||||
this.$eventBus.$on(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
|
||||
}
|
||||
this.$eventBus.$on('modal-hotkey', this.hotkey)
|
||||
},
|
||||
unregisterListeners() {
|
||||
if (this.libraryItem) {
|
||||
this.$eventBus.$on(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
|
||||
}
|
||||
this.$eventBus.$off('modal-hotkey', this.hotkey)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,6 +18,23 @@
|
||||
<p dir="auto" class="text-lg font-semibold mb-6">{{ title }}</p>
|
||||
<div v-if="description" dir="auto" class="default-style" v-html="description" />
|
||||
<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>
|
||||
</modals-modal>
|
||||
</template>
|
||||
@@ -54,7 +71,7 @@ export default {
|
||||
return this.episode.description || ''
|
||||
},
|
||||
media() {
|
||||
return this.libraryItem ? this.libraryItem.media || {} : {}
|
||||
return this.libraryItem?.media || {}
|
||||
},
|
||||
mediaMetadata() {
|
||||
return this.media.metadata || {}
|
||||
@@ -65,6 +82,14 @@ export default {
|
||||
podcastAuthor() {
|
||||
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() {
|
||||
return this.$store.getters['libraries/getBookCoverAspectRatio']
|
||||
}
|
||||
|
||||
@@ -163,13 +163,10 @@ export default {
|
||||
|
||||
this.isProcessing = false
|
||||
if (updateResult) {
|
||||
if (updateResult) {
|
||||
this.$toast.success(this.$strings.ToastItemUpdateSuccess)
|
||||
return true
|
||||
} else {
|
||||
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
|
||||
}
|
||||
this.$toast.success(this.$strings.ToastItemUpdateSuccess)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
|
||||
|
||||
<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 v-if="currentFeed.meta" class="mt-5">
|
||||
@@ -111,8 +111,11 @@ export default {
|
||||
userIsAdminOrUp() {
|
||||
return this.$store.getters['user/getIsAdminOrUp']
|
||||
},
|
||||
feedUrl() {
|
||||
return this.currentFeed ? `${window.origin}${this.$config.routerBasePath}${this.currentFeed.feedUrl}` : ''
|
||||
},
|
||||
demoFeedUrl() {
|
||||
return `${window.origin}/feed/${this.newFeedSlug}`
|
||||
return `${window.origin}${this.$config.routerBasePath}/feed/${this.newFeedSlug}`
|
||||
},
|
||||
isHttp() {
|
||||
return window.origin.startsWith('http://')
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
|
||||
|
||||
<div class="w-full relative">
|
||||
<ui-text-input v-model="feed.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>
|
||||
<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(feedUrl)">content_copy</span>
|
||||
</div>
|
||||
|
||||
<div v-if="feed.meta" class="mt-5">
|
||||
@@ -70,6 +70,9 @@ export default {
|
||||
},
|
||||
_feed() {
|
||||
return this.feed || {}
|
||||
},
|
||||
feedUrl() {
|
||||
return this.feed ? `${window.origin}${this.$config.routerBasePath}${this.feed.feedUrl}` : ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</ui-tooltip>
|
||||
|
||||
<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>
|
||||
</button>
|
||||
</ui-tooltip>
|
||||
@@ -64,6 +64,8 @@
|
||||
</div>
|
||||
|
||||
<modals-chapters-modal v-model="showChaptersModal" :current-chapter="currentChapter" :playback-rate="playbackRate" :chapters="chapters" @select="selectChapter" />
|
||||
|
||||
<modals-player-settings-modal v-model="showPlayerSettingsModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -96,6 +98,7 @@ export default {
|
||||
audioEl: null,
|
||||
seekLoading: false,
|
||||
showChaptersModal: false,
|
||||
showPlayerSettingsModal: false,
|
||||
currentTime: 0,
|
||||
duration: 0
|
||||
}
|
||||
@@ -315,6 +318,9 @@ export default {
|
||||
if (!this.chapters.length) return
|
||||
this.showChaptersModal = !this.showChaptersModal
|
||||
},
|
||||
showPlayerSettings() {
|
||||
this.showPlayerSettingsModal = !this.showPlayerSettingsModal
|
||||
},
|
||||
init() {
|
||||
this.playbackRate = this.$store.getters['user/getUserSetting']('playbackRate') || 1
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="heatmap" class="w-full">
|
||||
<div class="mx-auto" :style="{ height: innerHeight + 160 + 'px', width: innerWidth + 52 + 'px' }" style="background-color: rgba(13, 17, 23, 0)">
|
||||
<p class="mb-2 px-1 text-sm text-gray-200">{{ $getString('MessageListeningSessionsInTheLastYear', [Object.values(daysListening).length]) }}</p>
|
||||
<p class="mb-2 px-1 text-sm text-gray-200">{{ $getString('MessageDaysListenedInTheLastYear', [daysListenedInTheLastYear]) }}</p>
|
||||
<div class="border border-white border-opacity-25 rounded py-2 w-full" style="background-color: #232323" :style="{ height: innerHeight + 80 + 'px' }">
|
||||
<div :style="{ width: innerWidth + 'px', height: innerHeight + 'px' }" class="ml-10 mt-5 absolute" @mouseover="mouseover" @mouseout="mouseout">
|
||||
<div v-for="dayLabel in dayLabels" :key="dayLabel.label" :style="dayLabel.style" class="absolute top-0 left-0 text-gray-300">{{ dayLabel.label }}</div>
|
||||
@@ -37,6 +37,7 @@ export default {
|
||||
innerHeight: 13 * 7,
|
||||
blockWidth: 13,
|
||||
data: [],
|
||||
daysListenedInTheLastYear: 0,
|
||||
monthLabels: [],
|
||||
tooltipEl: null,
|
||||
tooltipTextEl: null,
|
||||
@@ -193,46 +194,47 @@ export default {
|
||||
buildData() {
|
||||
this.data = []
|
||||
|
||||
var maxValue = 0
|
||||
var minValue = 0
|
||||
Object.values(this.daysListening).forEach((val) => {
|
||||
if (val > maxValue) maxValue = val
|
||||
if (!minValue || val < minValue) minValue = val
|
||||
})
|
||||
const range = maxValue - minValue + 0.01
|
||||
let maxValue = 0
|
||||
let minValue = 0
|
||||
|
||||
const dates = []
|
||||
for (let i = 0; i < this.daysToShow + 1; i++) {
|
||||
const col = Math.floor(i / 7)
|
||||
const row = i % 7
|
||||
|
||||
const date = i === 0 ? this.firstWeekStart : this.$addDaysToDate(this.firstWeekStart, i)
|
||||
const dateString = this.$formatJsDate(date, 'yyyy-MM-dd')
|
||||
const datePretty = this.$formatJsDate(date, 'MMM d, yyyy')
|
||||
const monthString = this.$formatJsDate(date, 'MMM')
|
||||
const value = this.daysListening[dateString] || 0
|
||||
const x = col * 13
|
||||
const y = row * 13
|
||||
const dateObj = {
|
||||
col: Math.floor(i / 7),
|
||||
row: i % 7,
|
||||
date,
|
||||
dateString,
|
||||
datePretty: this.$formatJsDate(date, 'MMM d, yyyy'),
|
||||
monthString: this.$formatJsDate(date, 'MMM'),
|
||||
dayOfMonth: Number(dateString.split('-').pop()),
|
||||
yearString: dateString.split('-').shift(),
|
||||
value: this.daysListening[dateString] || 0
|
||||
}
|
||||
dates.push(dateObj)
|
||||
|
||||
var bgColor = this.bgColors[0]
|
||||
var outlineColor = this.outlineColors[0]
|
||||
if (value) {
|
||||
if (dateObj.value > 0) {
|
||||
this.daysListenedInTheLastYear++
|
||||
if (dateObj.value > maxValue) maxValue = dateObj.value
|
||||
if (!minValue || dateObj.value < minValue) minValue = dateObj.value
|
||||
}
|
||||
}
|
||||
const range = maxValue - minValue + 0.01
|
||||
|
||||
for (const dateObj of dates) {
|
||||
let bgColor = this.bgColors[0]
|
||||
let outlineColor = this.outlineColors[0]
|
||||
if (dateObj.value) {
|
||||
outlineColor = this.outlineColors[1]
|
||||
var percentOfAvg = (value - minValue) / range
|
||||
var bgIndex = Math.floor(percentOfAvg * 4) + 1
|
||||
const percentOfAvg = (dateObj.value - minValue) / range
|
||||
const bgIndex = Math.floor(percentOfAvg * 4) + 1
|
||||
bgColor = this.bgColors[bgIndex] || 'red'
|
||||
}
|
||||
|
||||
this.data.push({
|
||||
date,
|
||||
dateString,
|
||||
datePretty,
|
||||
monthString,
|
||||
dayOfMonth: Number(dateString.split('-').pop()),
|
||||
yearString: dateString.split('-').shift(),
|
||||
value,
|
||||
col,
|
||||
row,
|
||||
style: `transform:translate(${x}px,${y}px);background-color:${bgColor};outline:1px solid ${outlineColor};outline-offset:-1px;`
|
||||
...dateObj,
|
||||
style: `transform:translate(${dateObj.col * 13}px,${dateObj.row * 13}px);background-color:${bgColor};outline:1px solid ${outlineColor};outline-offset:-1px;`
|
||||
})
|
||||
}
|
||||
|
||||
@@ -260,6 +262,7 @@ export default {
|
||||
const heatmapEl = document.getElementById('heatmap')
|
||||
this.contentWidth = heatmapEl.clientWidth
|
||||
this.maxInnerWidth = this.contentWidth - 52
|
||||
this.daysListenedInTheLastYear = 0
|
||||
this.buildData()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="processing" class="max-w-[800px] h-80 md:h-[800px] mx-auto flex items-center justify-center">
|
||||
<div v-if="processing" role="img" :aria-label="$strings.MessageLoading" class="max-w-[800px] h-80 md:h-[800px] mx-auto flex items-center justify-center">
|
||||
<widgets-loading-spinner />
|
||||
</div>
|
||||
<img v-else-if="dataUrl" :src="dataUrl" class="mx-auto" />
|
||||
<img v-else-if="dataUrl" :src="dataUrl" class="mx-auto" :aria-label="$getString('LabelPersonalYearReview', [variant + 1])" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<p class="hidden md:block text-xl font-semibold">{{ $getString('HeaderYearReview', [yearInReviewYear]) }}</p>
|
||||
<h1 class="hidden md:block text-xl font-semibold">{{ $getString('HeaderYearReview', [yearInReviewYear]) }}</h1>
|
||||
<div class="hidden md:block flex-grow" />
|
||||
<ui-btn class="w-full md:w-auto" @click.stop="clickShowYearInReview">{{ showYearInReview ? $strings.LabelYearReviewHide : $strings.LabelYearReviewShow }}</ui-btn>
|
||||
</div>
|
||||
@@ -16,17 +16,22 @@
|
||||
<div v-if="showYearInReview">
|
||||
<div class="w-full h-px bg-slate-200/10 my-4" />
|
||||
|
||||
<div class="flex items-center justify-center mb-2 max-w-[800px] mx-auto">
|
||||
<div v-if="availableYears.length > 1" class="mb-2 py-2 max-w-[800px] mx-auto">
|
||||
<!-- year selector -->
|
||||
<ui-dropdown v-model="yearInReviewYear" small :items="availableYears" :disabled="processingYearInReview" class="max-w-24" @input="yearInReviewYearChanged" />
|
||||
</div>
|
||||
|
||||
<div role="toolbar" class="flex items-center justify-center mb-2 max-w-[800px] mx-auto">
|
||||
<!-- previous button -->
|
||||
<ui-btn small :disabled="!yearInReviewVariant || processingYearInReview" class="inline-flex items-center font-semibold" @click="yearInReviewVariant--">
|
||||
<ui-btn small :disabled="!yearInReviewVariant || processingYearInReview" :aria-label="$strings.ButtonPrevious" class="inline-flex items-center font-semibold" @click="yearInReviewVariant--">
|
||||
<span class="material-symbols text-lg sm:pr-1 py-px sm:py-0">chevron_left</span>
|
||||
<span class="hidden sm:inline-block pr-2">{{ $strings.ButtonPrevious }}</span>
|
||||
</ui-btn>
|
||||
<!-- share button -->
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReview" class="inline-flex sm:hidden items-center font-semibold ml-1 sm:ml-2" @click="shareYearInReview">{{ $strings.ButtonShare }} </ui-btn>
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReview" class="inline-flex items-center font-semibold ml-1 sm:ml-2" @click="shareYearInReview">{{ $strings.ButtonShare }} </ui-btn>
|
||||
|
||||
<div class="flex-grow" />
|
||||
<p class="hidden sm:block text-lg font-semibold">{{ $getString('LabelPersonalYearReview', [yearInReviewVariant + 1]) }}</p>
|
||||
<h2 class="hidden sm:block text-lg font-semibold">{{ $getString('LabelPersonalYearReview', [yearInReviewVariant + 1]) }}</h2>
|
||||
<p class="block sm:hidden text-lg font-semibold">{{ yearInReviewVariant + 1 }}</p>
|
||||
<div class="flex-grow" />
|
||||
|
||||
@@ -36,7 +41,7 @@
|
||||
<span class="material-symbols sm:!hidden text-lg py-px">refresh</span>
|
||||
</ui-btn>
|
||||
<!-- next button -->
|
||||
<ui-btn small :disabled="yearInReviewVariant >= 2 || processingYearInReview" class="inline-flex items-center font-semibold" @click="yearInReviewVariant++">
|
||||
<ui-btn small :disabled="yearInReviewVariant >= 2 || processingYearInReview" :aria-label="$strings.ButtonNext" class="inline-flex items-center font-semibold" @click="yearInReviewVariant++">
|
||||
<span class="hidden sm:inline-block pl-2">{{ $strings.ButtonNext }}</span>
|
||||
<span class="material-symbols text-lg sm:pl-1 py-px sm:py-0">chevron_right</span>
|
||||
</ui-btn>
|
||||
@@ -46,23 +51,23 @@
|
||||
<!-- your year in review short -->
|
||||
<div class="w-full max-w-[800px] mx-auto my-4">
|
||||
<!-- share button -->
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReviewShort" class="inline-flex sm:hidden items-center font-semibold mb-1" @click="shareYearInReviewShort">{{ $strings.ButtonShare }}</ui-btn>
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReviewShort" class="inline-flex items-center font-semibold mb-1" @click="shareYearInReviewShort">{{ $strings.ButtonShare }}</ui-btn>
|
||||
<stats-year-in-review-short ref="yearInReviewShort" :year="yearInReviewYear" :processing.sync="processingYearInReviewShort" />
|
||||
</div>
|
||||
|
||||
<!-- your server in review -->
|
||||
<div v-if="isAdminOrUp" class="w-full max-w-[800px] mx-auto mb-2 mt-4 border-t pt-4 border-white/10">
|
||||
<div v-if="isAdminOrUp" role="toolbar" class="w-full max-w-[800px] mx-auto mb-2 mt-4 border-t pt-4 border-white/10">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<!-- previous button -->
|
||||
<ui-btn small :disabled="!yearInReviewServerVariant || processingYearInReviewServer" class="inline-flex items-center font-semibold" @click="yearInReviewServerVariant--">
|
||||
<ui-btn small :disabled="!yearInReviewServerVariant || processingYearInReviewServer" :aria-label="$strings.ButtonPrevious" class="inline-flex items-center font-semibold" @click="yearInReviewServerVariant--">
|
||||
<span class="material-symbols text-lg sm:pr-1 py-px sm:py-0">chevron_left</span>
|
||||
<span class="hidden sm:inline-block pr-2">{{ $strings.ButtonPrevious }}</span>
|
||||
</ui-btn>
|
||||
<!-- share button -->
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReviewServer" class="inline-flex sm:hidden items-center font-semibold ml-1 sm:ml-2" @click="shareYearInReviewServer">{{ $strings.ButtonShare }} </ui-btn>
|
||||
<ui-btn v-if="showShareButton" small :disabled="processingYearInReviewServer" class="inline-flex items-center font-semibold ml-1 sm:ml-2" @click="shareYearInReviewServer">{{ $strings.ButtonShare }} </ui-btn>
|
||||
|
||||
<div class="flex-grow" />
|
||||
<p class="hidden sm:block text-lg font-semibold">{{ $getString('LabelServerYearReview', [yearInReviewServerVariant + 1]) }}</p>
|
||||
<h2 class="hidden sm:block text-lg font-semibold">{{ $getString('LabelServerYearReview', [yearInReviewServerVariant + 1]) }}</h2>
|
||||
<p class="block sm:hidden text-lg font-semibold">{{ yearInReviewServerVariant + 1 }}</p>
|
||||
<div class="flex-grow" />
|
||||
|
||||
@@ -72,7 +77,7 @@
|
||||
<span class="material-symbols sm:!hidden text-lg py-px">refresh</span>
|
||||
</ui-btn>
|
||||
<!-- next button -->
|
||||
<ui-btn small :disabled="yearInReviewServerVariant >= 2 || processingYearInReviewServer" class="inline-flex items-center font-semibold" @click="yearInReviewServerVariant++">
|
||||
<ui-btn small :disabled="yearInReviewServerVariant >= 2 || processingYearInReviewServer" :aria-label="$strings.ButtonNext" class="inline-flex items-center font-semibold" @click="yearInReviewServerVariant++">
|
||||
<span class="hidden sm:inline-block pl-2">{{ $strings.ButtonNext }}</span>
|
||||
<span class="material-symbols text-lg sm:pl-1 py-px sm:py-0">chevron_right</span>
|
||||
</ui-btn>
|
||||
@@ -88,6 +93,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showYearInReview: false,
|
||||
availableYears: [],
|
||||
yearInReviewYear: 0,
|
||||
yearInReviewVariant: 0,
|
||||
yearInReviewServerVariant: 0,
|
||||
@@ -100,6 +106,9 @@ export default {
|
||||
computed: {
|
||||
isAdminOrUp() {
|
||||
return this.$store.getters['user/getIsAdminOrUp']
|
||||
},
|
||||
user() {
|
||||
return this.$store.state.user.user
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -112,25 +121,57 @@ export default {
|
||||
shareYearInReviewShort() {
|
||||
this.$refs.yearInReviewShort.share()
|
||||
},
|
||||
yearInReviewYearChanged() {
|
||||
this.$nextTick(() => {
|
||||
this.refreshYearInReview()
|
||||
this.refreshYearInReviewServer()
|
||||
})
|
||||
},
|
||||
refreshYearInReviewServer() {
|
||||
this.$refs.yearInReviewServer.refresh()
|
||||
if (this.$refs.yearInReviewServer != null) {
|
||||
this.$refs.yearInReviewServer.refresh()
|
||||
}
|
||||
},
|
||||
refreshYearInReview() {
|
||||
this.$refs.yearInReview.refresh()
|
||||
this.$refs.yearInReviewShort.refresh()
|
||||
if (this.$refs.yearInReview != null && this.$refs.yearInReviewShort != null) {
|
||||
this.$refs.yearInReview.refresh()
|
||||
this.$refs.yearInReviewShort.refresh()
|
||||
}
|
||||
},
|
||||
clickShowYearInReview() {
|
||||
this.showYearInReview = !this.showYearInReview
|
||||
},
|
||||
getAvailableYears() {
|
||||
if (this.user) {
|
||||
const oldestDate = this.user.createdAt
|
||||
if (oldestDate) {
|
||||
const date = new Date(oldestDate)
|
||||
const oldestYear = date.getFullYear()
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
const years = []
|
||||
for (let year = currentYear; year >= oldestYear; year--) {
|
||||
years.push({ value: year, text: year.toString() })
|
||||
}
|
||||
|
||||
return years
|
||||
}
|
||||
}
|
||||
// Fallback on error
|
||||
return [{ value: this.yearInReviewYear, text: this.yearInReviewYear.toString() }]
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.yearInReviewYear = new Date().getFullYear()
|
||||
|
||||
// When not December show previous year
|
||||
if (new Date().getMonth() < 11) {
|
||||
this.yearInReviewYear--
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.availableYears = this.getAvailableYears()
|
||||
|
||||
if (typeof navigator.share !== 'undefined' && navigator.share) {
|
||||
this.showShareButton = true
|
||||
} else {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="processing" class="max-w-[800px] h-80 md:h-[800px] mx-auto flex items-center justify-center">
|
||||
<div v-if="processing" role="img" :aria-label="$strings.MessageLoading" class="max-w-[800px] h-80 md:h-[800px] mx-auto flex items-center justify-center">
|
||||
<widgets-loading-spinner />
|
||||
</div>
|
||||
<img v-else-if="dataUrl" :src="dataUrl" class="mx-auto" />
|
||||
<img v-else-if="dataUrl" :src="dataUrl" class="mx-auto" :aria-label="$getString('LabelServerYearReview', [variant + 1])" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ export default {
|
||||
this.users = res.users.sort((a, b) => {
|
||||
return a.createdAt - b.createdAt
|
||||
})
|
||||
this.$emit('numUsers', this.users.length)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed', error)
|
||||
|
||||
@@ -218,7 +218,6 @@ export default {
|
||||
this.$toast.success(this.$strings.ToastPlaylistRemoveSuccess)
|
||||
} else {
|
||||
console.log(`Item removed from playlist`, updatedPlaylist)
|
||||
this.$toast.success(this.$strings.ToastPlaylistUpdateSuccess)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
</template>
|
||||
</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">
|
||||
<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" />
|
||||
@@ -515,6 +514,10 @@ export default {
|
||||
}
|
||||
},
|
||||
filterSortChanged() {
|
||||
// Save filterKey and sortKey to local storage
|
||||
localStorage.setItem('podcastEpisodesFilter', this.filterKey)
|
||||
localStorage.setItem('podcastEpisodesSortBy', this.sortKey + (this.sortDesc ? '-desc' : ''))
|
||||
|
||||
this.init()
|
||||
},
|
||||
refresh() {
|
||||
@@ -537,6 +540,11 @@ export default {
|
||||
}
|
||||
},
|
||||
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.initListeners()
|
||||
this.init()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="relative h-9 w-9" v-click-outside="clickOutsideObj">
|
||||
<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>
|
||||
</button>
|
||||
<div v-else class="h-full w-full flex items-center justify-center">
|
||||
@@ -10,12 +10,12 @@
|
||||
</slot>
|
||||
|
||||
<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-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>
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
v-if="mouseoverItemIndex === index"
|
||||
:key="`subitems-${index}`"
|
||||
@@ -25,14 +25,14 @@
|
||||
:class="openSubMenuLeft ? 'rounded-l-md' : 'rounded-r-md'"
|
||||
: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>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="relative w-full" v-click-outside="clickOutsideObj">
|
||||
<p v-if="label" class="text-sm font-semibold px-1" :class="disabled ? 'text-gray-300' : ''">{{ label }}</p>
|
||||
<button type="button" :aria-label="longLabel" :disabled="disabled" class="relative w-full border rounded shadow-sm pl-3 pr-8 py-2 text-left sm:text-sm" :class="buttonClass" aria-haspopup="listbox" aria-expanded="true" @click.stop.prevent="clickShowMenu">
|
||||
<button type="button" :aria-label="longLabel" :disabled="disabled" class="relative w-full border rounded shadow-sm pl-3 pr-8 py-2 text-left sm:text-sm" :class="buttonClass" aria-haspopup="menu" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
||||
<span class="flex items-center">
|
||||
<span class="block truncate font-sans" :class="{ 'font-semibold': selectedSubtext, 'text-sm': small }">{{ selectedText }}</span>
|
||||
<span v-if="selectedSubtext">: </span>
|
||||
@@ -13,9 +13,9 @@
|
||||
</button>
|
||||
|
||||
<transition name="menu">
|
||||
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full bg-primary border border-black-200 shadow-lg rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto sm:text-sm" tabindex="-1" role="listbox" :style="{ maxHeight: menuMaxHeight }">
|
||||
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full bg-primary border border-black-200 shadow-lg rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto sm:text-sm" tabindex="-1" role="menu" :style="{ maxHeight: menuMaxHeight }">
|
||||
<template v-for="item in itemsToShow">
|
||||
<li :key="item.value" class="text-gray-100 relative py-2 cursor-pointer hover:bg-black-400" :id="'listbox-option-' + item.value" role="option" tabindex="0" @keyup.enter="clickedOption(item.value)" @click="clickedOption(item.value)">
|
||||
<li :key="item.value" class="text-gray-100 relative py-2 cursor-pointer hover:bg-black-400" role="menuitem" tabindex="0" @keyup.enter="clickedOption(item.value)" @click="clickedOption(item.value)">
|
||||
<div class="flex items-center">
|
||||
<span class="ml-3 block truncate font-sans text-sm" :class="{ 'font-semibold': item.subtext }">{{ item.text }}</span>
|
||||
<span v-if="item.subtext">: </span>
|
||||
@@ -119,4 +119,4 @@ export default {
|
||||
},
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
<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" />
|
||||
@@ -28,7 +28,8 @@ export default {
|
||||
size: {
|
||||
type: Number,
|
||||
default: 9
|
||||
}
|
||||
},
|
||||
ariaLabel: String
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
type="button"
|
||||
: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"
|
||||
aria-haspopup="listbox"
|
||||
aria-haspopup="menu"
|
||||
:aria-expanded="showMenu"
|
||||
:aria-label="$strings.ButtonLibrary + ': ' + currentLibrary.name"
|
||||
@click.stop.prevent="clickShowMenu"
|
||||
@@ -16,9 +16,9 @@
|
||||
</button>
|
||||
|
||||
<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">
|
||||
<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">
|
||||
<ui-library-icon :icon="library.icon" class="mr-1.5" />
|
||||
<span class="font-normal block truncate font-sans text-sm">{{ library.name }}</span>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">{{ label }}</p>
|
||||
<label :for="identifier" class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">{{ label }}</label>
|
||||
<div ref="wrapper" class="relative">
|
||||
<form @submit.prevent="submitForm">
|
||||
<div ref="inputWrapper" style="min-height: 36px" class="flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-1" :class="wrapperClass" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent>
|
||||
<div v-for="item in selected" :key="item" class="rounded-full px-2 py-1 mx-0.5 my-0.5 text-xs bg-bg flex flex-nowrap break-all items-center relative">
|
||||
<div v-if="!disabled" class="w-full h-full rounded-full absolute top-0 left-0 px-1 bg-bg bg-opacity-75 flex items-center justify-end opacity-0 hover:opacity-100">
|
||||
<span v-if="showEdit" class="material-symbols text-white hover:text-warning cursor-pointer" style="font-size: 1.1rem" @click.stop="editItem(item)">edit</span>
|
||||
<span class="material-symbols text-white hover:text-error cursor-pointer" style="font-size: 1.1rem" @click.stop="removeItem(item)">close</span>
|
||||
<div ref="inputWrapper" role="list" style="min-height: 36px" class="flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-1" :class="wrapperClass" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent>
|
||||
<div v-for="item in selected" :key="item" role="listitem" class="rounded-full px-2 py-1 mx-0.5 my-0.5 text-xs bg-bg flex flex-nowrap break-all items-center relative">
|
||||
<div v-if="!disabled" class="w-full h-full rounded-full absolute top-0 left-0 px-1 bg-bg bg-opacity-75 flex items-center justify-end opacity-0 hover:opacity-100" :class="{ 'opacity-100': inputFocused }">
|
||||
<button v-if="showEdit" type="button" :aria-label="$strings.ButtonEdit" class="material-symbols text-white hover:text-warning cursor-pointer" style="font-size: 1.1rem" @click.stop="editItem(item)">edit</button>
|
||||
<button type="button" :aria-label="$strings.ButtonRemove" class="material-symbols text-white hover:text-error focus:text-error cursor-pointer" style="font-size: 1.1rem" @click.stop="removeItem(item)" @keydown.enter.stop.prevent="removeItem(item)" @focus="setInputFocused(true)" @blur="setInputFocused(false)" tabindex="0">close</button>
|
||||
</div>
|
||||
{{ item }}
|
||||
</div>
|
||||
<input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" class="h-full bg-primary focus:outline-none px-1 w-6" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
|
||||
<input v-show="!readonly" v-model="textInput" ref="input" :id="identifier" :disabled="disabled" class="h-full bg-primary focus:outline-none px-1 w-6" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -66,7 +66,8 @@ export default {
|
||||
typingTimeout: null,
|
||||
isFocused: false,
|
||||
menu: null,
|
||||
filteredItems: null
|
||||
filteredItems: null,
|
||||
inputFocused: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -100,6 +101,9 @@ export default {
|
||||
}
|
||||
|
||||
return this.filteredItems
|
||||
},
|
||||
identifier() {
|
||||
return Math.random().toString(36).substring(2)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -129,6 +133,9 @@ export default {
|
||||
}, 100)
|
||||
this.setInputWidth()
|
||||
},
|
||||
setInputFocused(focused) {
|
||||
this.inputFocused = focused
|
||||
},
|
||||
setInputWidth() {
|
||||
setTimeout(() => {
|
||||
var value = this.$refs.input.value
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">{{ label }}</p>
|
||||
<label :for="identifier" class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">{{ label }}</label>
|
||||
<div ref="wrapper" class="relative">
|
||||
<form @submit.prevent="submitForm">
|
||||
<div ref="inputWrapper" style="min-height: 36px" class="flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-0.5" :class="wrapperClass" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent>
|
||||
<div v-for="item in selected" :key="item.id" class="rounded-full px-2 py-0.5 m-0.5 text-xs bg-bg flex flex-nowrap whitespace-nowrap items-center justify-center relative min-w-12">
|
||||
<div v-if="!disabled" class="w-full h-full rounded-full absolute top-0 left-0 opacity-0 hover:opacity-100 px-1 bg-bg bg-opacity-75 flex items-center justify-end cursor-pointer">
|
||||
<span v-if="showEdit" class="material-symbols text-base text-white hover:text-warning mr-1" @click.stop="editItem(item)">edit</span>
|
||||
<span class="material-symbols text-white hover:text-error" style="font-size: 1.1rem" @click.stop="removeItem(item.id)">close</span>
|
||||
<div ref="inputWrapper" role="list" style="min-height: 36px" class="flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-0.5" :class="wrapperClass" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent>
|
||||
<div v-for="item in selected" :key="item.id" role="listitem" class="rounded-full px-2 py-0.5 m-0.5 text-xs bg-bg flex flex-nowrap whitespace-nowrap items-center justify-center relative min-w-12">
|
||||
<div v-if="!disabled" class="w-full h-full rounded-full absolute top-0 left-0 opacity-0 hover:opacity-100 px-1 bg-bg bg-opacity-75 flex items-center justify-end cursor-pointer" :class="{ 'opacity-100': inputFocused }">
|
||||
<button v-if="showEdit" type="button" :aria-label="$strings.ButtonEdit" class="material-symbols text-base text-white hover:text-warning focus:text-warning mr-1" @click.stop="editItem(item)" @keydown.enter.stop.prevent="editItem(item)" @focus="setInputFocused(true)" @blur="setInputFocused(false)" tabindex="0">edit</button>
|
||||
<button type="button" :aria-label="$strings.ButtonRemove" class="material-symbols text-white hover:text-error focus:text-error" style="font-size: 1.1rem" @click.stop="removeItem(item.id)" @keydown.enter.stop="removeItem(item.id)" @focus="setInputFocused(true)" @blur="setInputFocused(false)" tabindex="0">close</button>
|
||||
</div>
|
||||
{{ item[textKey] }}
|
||||
</div>
|
||||
<div v-if="showEdit && !disabled" class="rounded-full cursor-pointer w-6 h-6 mx-0.5 bg-bg flex items-center justify-center">
|
||||
<span class="material-symbols text-white hover:text-success pt-px pr-px" style="font-size: 1.1rem" @click.stop="addItem">add</span>
|
||||
<button type="button" :aria-label="$strings.ButtonAdd" class="material-symbols text-white hover:text-success focus:text-success pt-px pr-px" style="font-size: 1.1rem" @click.stop="addItem" @keydown.enter.stop="addItem" tabindex="0">add</button>
|
||||
</div>
|
||||
<input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" class="h-full bg-primary focus:outline-none px-1 w-6" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
|
||||
<input v-show="!readonly" v-model="textInput" ref="input" :id="identifier" :disabled="disabled" class="h-full bg-primary focus:outline-none px-1 w-6" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -65,6 +65,7 @@ export default {
|
||||
currentSearch: null,
|
||||
typingTimeout: null,
|
||||
isFocused: false,
|
||||
inputFocused: false,
|
||||
menu: null,
|
||||
items: []
|
||||
}
|
||||
@@ -102,6 +103,9 @@ export default {
|
||||
},
|
||||
filterData() {
|
||||
return this.$store.state.libraries.filterData || {}
|
||||
},
|
||||
identifier() {
|
||||
return Math.random().toString(36).substring(2)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -114,6 +118,9 @@ export default {
|
||||
getIsSelected(itemValue) {
|
||||
return !!this.selected.find((i) => i.id === itemValue)
|
||||
},
|
||||
setInputFocused(focused) {
|
||||
this.inputFocused = focused
|
||||
},
|
||||
search() {
|
||||
if (!this.textInput) return
|
||||
this.currentSearch = this.textInput
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
<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" />
|
||||
|
||||
@@ -57,7 +57,8 @@ export default {
|
||||
inputName: String,
|
||||
showCopy: Boolean,
|
||||
step: [String, Number],
|
||||
min: [String, Number]
|
||||
min: [String, Number],
|
||||
customInputClass: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -82,6 +83,7 @@ export default {
|
||||
_list.push(`py-${this.paddingY}`)
|
||||
if (this.noSpinner) _list.push('no-spinner')
|
||||
if (this.textCenter) _list.push('text-center')
|
||||
if (this.customInputClass) _list.push(this.customInputClass)
|
||||
return _list.join(' ')
|
||||
},
|
||||
actualType() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<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">
|
||||
<span class="rounded-full border w-5 h-5 border-black-50 shadow transform transition-transform duration-100" :class="switchClassName"></span>
|
||||
<button :aria-labelledby="labeledBy" :aria-label="label" 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 border-black-50 shadow transform transition-transform duration-100" :style="{ width: cursorHeightWidth + 'px', height: cursorHeightWidth + 'px' }" :class="switchClassName"></span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -19,7 +19,12 @@ export default {
|
||||
default: 'primary'
|
||||
},
|
||||
disabled: Boolean,
|
||||
labeledBy: String
|
||||
labeledBy: String,
|
||||
label: String,
|
||||
size: {
|
||||
type: String,
|
||||
default: 'md'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
toggleValue: {
|
||||
@@ -37,6 +42,13 @@ export default {
|
||||
switchClassName() {
|
||||
var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white'
|
||||
return this.toggleValue ? 'translate-x-5 ' + bgColor : bgColor
|
||||
},
|
||||
cursorHeightWidth() {
|
||||
if (this.size === 'sm') return 16
|
||||
return 20
|
||||
},
|
||||
buttonWidth() {
|
||||
return this.cursorHeightWidth * 2
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<div class="flex items-center py-3e">
|
||||
<slot />
|
||||
<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>
|
||||
</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>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -71,8 +71,6 @@ export default {
|
||||
this.showSeriesForm = true
|
||||
},
|
||||
submitSeriesForm() {
|
||||
console.log('submit series form', this.value, this.selectedSeries)
|
||||
|
||||
if (!this.selectedSeries.name) {
|
||||
this.$toast.error('Must enter a series')
|
||||
return
|
||||
|
||||
@@ -57,9 +57,10 @@ export default {
|
||||
for (let entry of entries) {
|
||||
this.cardWidth = entry.borderBoxSize[0].inlineSize
|
||||
this.cardHeight = entry.borderBoxSize[0].blockSize
|
||||
this.resizeObserver.disconnect()
|
||||
this.$refs.bookshelf.removeChild(instance.$el)
|
||||
}
|
||||
this.coverHeight = instance.coverHeight
|
||||
this.resizeObserver.disconnect()
|
||||
this.$refs.bookshelf.removeChild(instance.$el)
|
||||
})
|
||||
instance.$el.style.visibility = 'hidden'
|
||||
instance.$el.style.position = 'absolute'
|
||||
@@ -131,10 +132,7 @@ export default {
|
||||
this.entityComponentRefs[index] = instance
|
||||
|
||||
instance.$mount()
|
||||
const shelfOffsetY = this.shelfPaddingHeight * this.sizeMultiplier
|
||||
const row = index % this.entitiesPerShelf
|
||||
const shelfOffsetX = row * this.totalEntityCardWidth + this.bookshelfMarginLeft
|
||||
instance.$el.style.transform = `translate3d(${shelfOffsetX}px, ${shelfOffsetY}px, 0px)`
|
||||
instance.$el.style.transform = this.entityTransform((index % this.entitiesPerShelf) + 1)
|
||||
instance.$el.classList.add('absolute', 'top-0', 'left-0')
|
||||
shelfEl.appendChild(instance.$el)
|
||||
|
||||
|
||||
@@ -28,10 +28,8 @@ export default {
|
||||
var validOtherFiles = []
|
||||
var ignoredFiles = []
|
||||
files.forEach((file) => {
|
||||
// var filetype = this.checkFileType(file.name)
|
||||
if (!file.filetype) ignoredFiles.push(file)
|
||||
else {
|
||||
// file.filetype = filetype
|
||||
if (file.filetype === 'audio' || (file.filetype === 'ebook' && mediaType === 'book')) validItemFiles.push(file)
|
||||
else validOtherFiles.push(file)
|
||||
}
|
||||
@@ -165,7 +163,7 @@ export default {
|
||||
|
||||
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) {
|
||||
audiobook.title = dirs.pop()
|
||||
if (dirs.length > 1) {
|
||||
@@ -189,7 +187,7 @@ export default {
|
||||
var firstAudioFile = podcast.itemFiles[0]
|
||||
if (!firstAudioFile.filepath) return podcast // No path
|
||||
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) {
|
||||
podcast.title = dirs.length > 1 ? dirs[1] : dirs[0]
|
||||
} else {
|
||||
@@ -212,13 +210,15 @@ export default {
|
||||
}
|
||||
var ignoredFiles = itemData.ignoredFiles
|
||||
var index = 1
|
||||
var items = itemData.items.filter((ab) => {
|
||||
if (!ab.itemFiles.length) {
|
||||
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++))
|
||||
var items = itemData.items
|
||||
.filter((ab) => {
|
||||
if (!ab.itemFiles.length) {
|
||||
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 {
|
||||
items,
|
||||
ignoredFiles
|
||||
@@ -259,7 +259,7 @@ export default {
|
||||
|
||||
otherFiles.forEach((file) => {
|
||||
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) {
|
||||
findItem.otherFiles.push(file)
|
||||
} else {
|
||||
@@ -270,18 +270,18 @@ export default {
|
||||
var items = []
|
||||
var index = 1
|
||||
// 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) => {
|
||||
return this.cleanItem({ itemFiles: [audioFile], otherFiles: [], ignoredFiles: [] }, mediaType, index++)
|
||||
})
|
||||
} else {
|
||||
items = Object.values(itemMap).map(i => this.cleanItem(i, mediaType, index++))
|
||||
items = Object.values(itemMap).map((i) => this.cleanItem(i, mediaType, index++))
|
||||
}
|
||||
|
||||
return {
|
||||
items,
|
||||
ignoredFiles: ignoredFiles
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "audiobookshelf-client",
|
||||
"version": "2.15.1",
|
||||
"version": "2.17.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "audiobookshelf-client",
|
||||
"version": "2.15.1",
|
||||
"version": "2.17.7",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@nuxtjs/axios": "^5.13.6",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "audiobookshelf-client",
|
||||
"version": "2.15.1",
|
||||
"version": "2.17.7",
|
||||
"buildNumber": 1,
|
||||
"description": "Self-hosted audiobook and podcast client",
|
||||
"main": "index.js",
|
||||
|
||||
@@ -32,9 +32,48 @@
|
||||
</form>
|
||||
</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">
|
||||
<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>
|
||||
|
||||
<modals-emails-user-e-reader-device-modal v-model="showEReaderDeviceModal" :existing-devices="revisedEreaderDevices" :ereader-device="selectedEReaderDevice" @update="ereaderDevicesUpdated" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -43,11 +82,20 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
password: null,
|
||||
newPassword: null,
|
||||
confirmPassword: null,
|
||||
changingPassword: false,
|
||||
selectedLanguage: ''
|
||||
selectedLanguage: '',
|
||||
newEReaderDevice: {
|
||||
name: '',
|
||||
email: ''
|
||||
},
|
||||
ereaderDevices: [],
|
||||
deletingDeviceName: null,
|
||||
selectedEReaderDevice: null,
|
||||
showEReaderDeviceModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -75,6 +123,12 @@ export default {
|
||||
},
|
||||
showChangePasswordForm() {
|
||||
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: {
|
||||
@@ -142,10 +196,52 @@ export default {
|
||||
this.$toast.error(this.$strings.ToastUnknownError)
|
||||
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() {
|
||||
this.selectedLanguage = this.$languageCodes.current
|
||||
this.ereaderDevices = this.$store.state.libraries.ereaderDevices || []
|
||||
}
|
||||
}
|
||||
</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" />
|
||||
<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" />
|
||||
|
||||
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
|
||||
@@ -164,6 +178,27 @@ export default {
|
||||
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: {
|
||||
@@ -325,7 +360,8 @@ export default {
|
||||
},
|
||||
init() {
|
||||
this.newAuthSettings = {
|
||||
...this.authSettings
|
||||
...this.authSettings,
|
||||
authOpenIDSubfolderForRedirectURLs: this.authSettings.authOpenIDSubfolderForRedirectURLs === undefined ? this.$config.routerBasePath : this.authSettings.authOpenIDSubfolderForRedirectURLs
|
||||
}
|
||||
this.enableLocalAuth = this.authMethods.includes('local')
|
||||
this.enableOpenIDAuth = this.authMethods.includes('openid')
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<div class="pt-4">
|
||||
<h2 class="font-semibold">{{ $strings.HeaderSettingsGeneral }}</h2>
|
||||
</div>
|
||||
<div class="flex items-end py-2">
|
||||
<ui-toggle-switch labeledBy="settings-store-cover-with-items" v-model="newServerSettings.storeCoverWithItem" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('storeCoverWithItem', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsStoreCoversWithItemHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsStoreCoversWithItemHelp" class="flex items-end py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsStoreCoversWithItem" v-model="newServerSettings.storeCoverWithItem" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('storeCoverWithItem', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsStoreCoversWithItemHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-store-cover-with-items">{{ $strings.LabelSettingsStoreCoversWithItem }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -16,9 +16,9 @@
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-store-metadata-with-items" v-model="newServerSettings.storeMetadataWithItem" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('storeMetadataWithItem', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsStoreMetadataWithItemHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsStoreMetadataWithItemHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsStoreMetadataWithItem" v-model="newServerSettings.storeMetadataWithItem" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('storeMetadataWithItem', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsStoreMetadataWithItemHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-store-metadata-with-items">{{ $strings.LabelSettingsStoreMetadataWithItem }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -26,9 +26,9 @@
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-sorting-ignore-prefixes" v-model="newServerSettings.sortingIgnorePrefix" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('sortingIgnorePrefix', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsSortingIgnorePrefixesHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsSortingIgnorePrefixesHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsSortingIgnorePrefixes" v-model="newServerSettings.sortingIgnorePrefix" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('sortingIgnorePrefix', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsSortingIgnorePrefixesHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-sorting-ignore-prefixes">{{ $strings.LabelSettingsSortingIgnorePrefixes }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -42,18 +42,13 @@
|
||||
</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">
|
||||
<h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-parse-subtitles" v-model="newServerSettings.scannerParseSubtitle" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerParseSubtitle', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsParseSubtitlesHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsParseSubtitlesHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsParseSubtitles" v-model="newServerSettings.scannerParseSubtitle" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerParseSubtitle', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsParseSubtitlesHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-parse-subtitles">{{ $strings.LabelSettingsParseSubtitles }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -61,9 +56,9 @@
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-find-covers" v-model="newServerSettings.scannerFindCovers" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerFindCovers', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsFindCoversHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsFindCoversHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsFindCovers" v-model="newServerSettings.scannerFindCovers" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerFindCovers', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsFindCoversHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-find-covers">{{ $strings.LabelSettingsFindCovers }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -75,9 +70,9 @@
|
||||
<ui-dropdown v-model="newServerSettings.scannerCoverProvider" small :items="providers" label="Cover Provider" @input="updateScannerCoverProvider" :disabled="updatingServerSettings" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-prefer-matched-metadata" v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsPreferMatchedMetadataHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsPreferMatchedMetadataHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsPreferMatchedMetadata" v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsPreferMatchedMetadataHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-prefer-matched-metadata">{{ $strings.LabelSettingsPreferMatchedMetadata }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
@@ -85,15 +80,29 @@
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch labeledBy="settings-disable-watcher" v-model="scannerEnableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', !val)" />
|
||||
<ui-tooltip :text="$strings.LabelSettingsEnableWatcherHelp">
|
||||
<div role="article" :aria-label="$strings.LabelSettingsEnableWatcherHelp" class="flex items-center py-2">
|
||||
<ui-toggle-switch :label="$strings.LabelSettingsEnableWatcher" v-model="scannerEnableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', !val)" />
|
||||
<ui-tooltip aria-hidden="true" :text="$strings.LabelSettingsEnableWatcherHelp">
|
||||
<p class="pl-4">
|
||||
<span id="settings-disable-watcher">{{ $strings.LabelSettingsEnableWatcher }}</span>
|
||||
<span class="material-symbols icon-text">info</span>
|
||||
</p>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="pt-4">
|
||||
<h2 class="font-semibold">{{ $strings.HeaderSettingsWebClient }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2">
|
||||
<ui-toggle-switch v-model="newServerSettings.chromecastEnabled" :label="$strings.LabelSettingsChromecastSupport" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
|
||||
<p aria-hidden="true" class="pl-4">{{ $strings.LabelSettingsChromecastSupport }}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center py-2 mb-2">
|
||||
<ui-toggle-switch v-model="newServerSettings.allowIframe" :label="$strings.LabelSettingsAllowIframe" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('allowIframe', val)" />
|
||||
<p aria-hidden="true" class="pl-4">{{ $strings.LabelSettingsAllowIframe }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1">
|
||||
@@ -324,21 +333,21 @@ export default {
|
||||
},
|
||||
updateServerSettings(payload) {
|
||||
this.updatingServerSettings = true
|
||||
this.$store
|
||||
.dispatch('updateServerSettings', payload)
|
||||
.then(() => {
|
||||
this.updatingServerSettings = false
|
||||
this.$store.dispatch('updateServerSettings', payload).then((response) => {
|
||||
this.updatingServerSettings = false
|
||||
|
||||
if (payload.language) {
|
||||
// Updating language after save allows for re-rendering
|
||||
this.$setLanguageCode(payload.language)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to update server settings', error)
|
||||
this.updatingServerSettings = false
|
||||
this.$toast.error(this.$strings.ToastFailedToUpdate)
|
||||
})
|
||||
if (response.error) {
|
||||
console.error('Failed to update server settins', response.error)
|
||||
this.$toast.error(response.error)
|
||||
this.initServerSettings()
|
||||
return
|
||||
}
|
||||
|
||||
if (payload.language) {
|
||||
// Updating language after save allows for re-rendering
|
||||
this.$setLanguageCode(payload.language)
|
||||
}
|
||||
})
|
||||
},
|
||||
initServerSettings() {
|
||||
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<tr v-for="feed in feeds" :key="feed.id" class="cursor-pointer h-12" @click="showFeed(feed)">
|
||||
<!-- -->
|
||||
<td>
|
||||
<img :src="coverUrl(feed)" class="h-full w-full" />
|
||||
<img :src="coverUrl(feed)" class="h-auto w-full" />
|
||||
</td>
|
||||
<!-- -->
|
||||
<td class="w-48 max-w-64 min-w-24 text-left truncate">
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
},
|
||||
coverUrl(feed) {
|
||||
if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
|
||||
return `${feed.feedUrl}/cover`
|
||||
return `${this.$config.routerBasePath}${feed.feedUrl}/cover`
|
||||
},
|
||||
async loadFeeds() {
|
||||
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" />
|
||||
</div>
|
||||
<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_forward_ios" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
|
||||
</div>
|
||||
@@ -103,7 +103,7 @@
|
||||
<div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
|
||||
|
||||
<!-- 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">
|
||||
<table class="userSessionsTable">
|
||||
<tr class="bg-primary bg-opacity-40">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<h1 class="text-xl pl-2">{{ username }}</h1>
|
||||
</div>
|
||||
<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)">
|
||||
<span class="material-symbols pl-2 text-base">content_copy</span>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
</table>
|
||||
<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" />
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
<div>
|
||||
<app-settings-content :header-text="$strings.HeaderUsers">
|
||||
<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">
|
||||
<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>
|
||||
@@ -13,7 +17,7 @@
|
||||
<ui-btn color="primary" small @click="setShowUserModal()">{{ $strings.ButtonAddUser }}</ui-btn>
|
||||
</template>
|
||||
|
||||
<tables-users-table class="pt-2" @edit="setShowUserModal" />
|
||||
<tables-users-table class="pt-2" @edit="setShowUserModal" @numUsers="(count) => (numUsers = count)" />
|
||||
</app-settings-content>
|
||||
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
|
||||
</div>
|
||||
@@ -29,7 +33,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
selectedAccount: null,
|
||||
showAccountModal: false
|
||||
showAccountModal: false,
|
||||
numUsers: 0
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
<!-- 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 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>
|
||||
</div>
|
||||
</button>
|
||||
</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>
|
||||
@@ -87,7 +87,7 @@
|
||||
</ui-btn>
|
||||
|
||||
<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 }}
|
||||
</ui-btn>
|
||||
|
||||
@@ -96,12 +96,12 @@
|
||||
</ui-tooltip>
|
||||
|
||||
<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 }}
|
||||
</ui-btn>
|
||||
|
||||
<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 v-if="!isPodcast" :text="userIsFinished ? $strings.MessageMarkAsNotFinished : $strings.MessageMarkAsFinished" direction="top">
|
||||
@@ -110,12 +110,12 @@
|
||||
|
||||
<!-- Only admin or root user can download new episodes -->
|
||||
<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-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="148" @action="contextMenuAction">
|
||||
<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>
|
||||
</button>
|
||||
</template>
|
||||
@@ -638,6 +638,11 @@ export default {
|
||||
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
||||
}
|
||||
},
|
||||
episodeDownloadQueueCleared(libraryItemId) {
|
||||
if (libraryItemId === this.libraryItemId) {
|
||||
this.episodeDownloadsQueued = []
|
||||
}
|
||||
},
|
||||
rssFeedOpen(data) {
|
||||
if (data.entityId === this.libraryItemId) {
|
||||
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_started', this.episodeDownloadStarted)
|
||||
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
||||
this.$root.socket.on('episode_download_queue_cleared', this.episodeDownloadQueueCleared)
|
||||
},
|
||||
beforeDestroy() {
|
||||
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_started', this.episodeDownloadStarted)
|
||||
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
||||
this.$root.socket.off('episode_download_queue_cleared', this.episodeDownloadQueueCleared)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -104,9 +104,6 @@ export default {
|
||||
this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id)
|
||||
}
|
||||
},
|
||||
episodeDownloadQueueUpdated(downloadQueueDetails) {
|
||||
this.episodeDownloadsQueued = downloadQueueDetails.queue.filter((q) => q.libraryId == this.libraryId)
|
||||
},
|
||||
async loadInitialDownloadQueue() {
|
||||
this.processing = true
|
||||
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_started', this.episodeDownloadStarted)
|
||||
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
|
||||
this.$root.socket.on('episode_download_queue_updated', this.episodeDownloadQueueUpdated)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -138,7 +134,6 @@ export default {
|
||||
this.$root.socket.off('episode_download_queued', this.episodeDownloadQueued)
|
||||
this.$root.socket.off('episode_download_started', this.episodeDownloadStarted)
|
||||
this.$root.socket.off('episode_download_finished', this.episodeDownloadFinished)
|
||||
this.$root.socket.off('episode_download_queue_updated', this.episodeDownloadQueueUpdated)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
<div class="w-full pt-16">
|
||||
<player-ui ref="audioPlayer" :chapters="chapters" :current-chapter="currentChapter" :paused="isPaused" :loading="!hasLoaded" :is-podcast="false" hide-bookmarks hide-sleep-timer @playPause="playPause" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setVolume="setVolume" @setPlaybackRate="setPlaybackRate" @seek="seek" />
|
||||
</div>
|
||||
|
||||
<ui-tooltip v-if="mediaItemShare.isDownloadable" direction="bottom" :text="$strings.LabelDownload" class="absolute top-0 left-0 m-4">
|
||||
<button aria-label="Download" class="text-gray-300 hover:text-white" @click="downloadShareItem"><span class="material-symbols text-2xl sm:text-3xl">download</span></button>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,6 +67,9 @@ export default {
|
||||
if (!this.playbackSession.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg`
|
||||
return `${this.$config.routerBasePath}/public/share/${this.mediaItemShare.slug}/cover`
|
||||
},
|
||||
downloadUrl() {
|
||||
return `${process.env.serverUrl}/public/share/${this.mediaItemShare.slug}/download`
|
||||
},
|
||||
audioTracks() {
|
||||
return (this.playbackSession.audioTracks || []).map((track) => {
|
||||
track.relativeContentUrl = track.contentUrl
|
||||
@@ -103,6 +110,84 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
mediaSessionPlay() {
|
||||
console.log('Media session play')
|
||||
this.play()
|
||||
},
|
||||
mediaSessionPause() {
|
||||
console.log('Media session pause')
|
||||
this.pause()
|
||||
},
|
||||
mediaSessionStop() {
|
||||
console.log('Media session stop')
|
||||
this.pause()
|
||||
},
|
||||
mediaSessionSeekBackward() {
|
||||
console.log('Media session seek backward')
|
||||
this.jumpBackward()
|
||||
},
|
||||
mediaSessionSeekForward() {
|
||||
console.log('Media session seek forward')
|
||||
this.jumpForward()
|
||||
},
|
||||
mediaSessionSeekTo(e) {
|
||||
console.log('Media session seek to', e)
|
||||
if (e.seekTime !== null && !isNaN(e.seekTime)) {
|
||||
this.seek(e.seekTime)
|
||||
}
|
||||
},
|
||||
mediaSessionPreviousTrack() {
|
||||
if (this.$refs.audioPlayer) {
|
||||
this.$refs.audioPlayer.prevChapter()
|
||||
}
|
||||
},
|
||||
mediaSessionNextTrack() {
|
||||
if (this.$refs.audioPlayer) {
|
||||
this.$refs.audioPlayer.nextChapter()
|
||||
}
|
||||
},
|
||||
updateMediaSessionPlaybackState() {
|
||||
if ('mediaSession' in navigator) {
|
||||
navigator.mediaSession.playbackState = this.isPlaying ? 'playing' : 'paused'
|
||||
}
|
||||
},
|
||||
setMediaSession() {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API
|
||||
if ('mediaSession' in navigator) {
|
||||
const chapterInfo = []
|
||||
if (this.chapters.length > 0) {
|
||||
this.chapters.forEach((chapter) => {
|
||||
chapterInfo.push({
|
||||
title: chapter.title,
|
||||
startTime: chapter.start
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: this.mediaItemShare.playbackSession.displayTitle || 'No title',
|
||||
artist: this.mediaItemShare.playbackSession.displayAuthor || 'Unknown',
|
||||
artwork: [
|
||||
{
|
||||
src: this.coverUrl
|
||||
}
|
||||
],
|
||||
chapterInfo
|
||||
})
|
||||
console.log('Set media session metadata', navigator.mediaSession.metadata)
|
||||
|
||||
navigator.mediaSession.setActionHandler('play', this.mediaSessionPlay)
|
||||
navigator.mediaSession.setActionHandler('pause', this.mediaSessionPause)
|
||||
navigator.mediaSession.setActionHandler('stop', this.mediaSessionStop)
|
||||
navigator.mediaSession.setActionHandler('seekbackward', this.mediaSessionSeekBackward)
|
||||
navigator.mediaSession.setActionHandler('seekforward', this.mediaSessionSeekForward)
|
||||
navigator.mediaSession.setActionHandler('seekto', this.mediaSessionSeekTo)
|
||||
navigator.mediaSession.setActionHandler('previoustrack', this.mediaSessionSeekBackward)
|
||||
navigator.mediaSession.setActionHandler('nexttrack', this.mediaSessionSeekForward)
|
||||
} else {
|
||||
console.warn('Media session not available')
|
||||
}
|
||||
},
|
||||
async coverImageLoaded(e) {
|
||||
if (!this.playbackSession.coverPath) return
|
||||
const fac = new FastAverageColor()
|
||||
@@ -119,19 +204,32 @@ export default {
|
||||
})
|
||||
},
|
||||
playPause() {
|
||||
if (this.isPlaying) {
|
||||
this.pause()
|
||||
} else {
|
||||
this.play()
|
||||
}
|
||||
},
|
||||
play() {
|
||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||
this.localAudioPlayer.playPause()
|
||||
this.localAudioPlayer.play()
|
||||
},
|
||||
pause() {
|
||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||
this.localAudioPlayer.pause()
|
||||
},
|
||||
jumpForward() {
|
||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||
const currentTime = this.localAudioPlayer.getCurrentTime()
|
||||
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() {
|
||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||
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) {
|
||||
if (!this.localAudioPlayer || !this.hasLoaded) return
|
||||
@@ -204,6 +302,7 @@ export default {
|
||||
} else {
|
||||
this.stopPlayInterval()
|
||||
}
|
||||
this.updateMediaSessionPlaybackState()
|
||||
},
|
||||
playerTimeUpdate(time) {
|
||||
this.setCurrentTime(time)
|
||||
@@ -245,9 +344,14 @@ export default {
|
||||
},
|
||||
playerFinished() {
|
||||
console.log('Player finished')
|
||||
},
|
||||
downloadShareItem() {
|
||||
this.$downloadFile(this.downloadUrl)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('user/loadUserSettings')
|
||||
|
||||
this.resize()
|
||||
window.addEventListener('resize', this.resize)
|
||||
window.addEventListener('keydown', this.keyDown)
|
||||
@@ -262,6 +366,8 @@ export default {
|
||||
this.localAudioPlayer.on('timeupdate', this.playerTimeUpdate.bind(this))
|
||||
this.localAudioPlayer.on('error', this.playerError.bind(this))
|
||||
this.localAudioPlayer.on('finished', this.playerFinished.bind(this))
|
||||
|
||||
this.setMediaSession()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<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">
|
||||
<!-- Library & folder picker -->
|
||||
<div class="flex my-6 -mx-2">
|
||||
<div class="w-1/5 px-2">
|
||||
<div class="flex flex-wrap my-6 md:-mx-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" />
|
||||
</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" />
|
||||
</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" />
|
||||
</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">
|
||||
<ui-toggle-switch v-model="fetchMetadata.enabled" class="inline-flex" />
|
||||
<span class="pl-2 text-base">{{ $strings.LabelAutoFetchMetadata }}</span>
|
||||
@@ -33,13 +33,13 @@
|
||||
</widgets-alert>
|
||||
|
||||
<!-- 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'">
|
||||
<p class="text-2xl text-center">{{ isDragging ? $strings.LabelUploaderDropFiles : $strings.LabelUploaderDragAndDrop }}</p>
|
||||
<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 : isIOS ? $strings.LabelUploaderDragAndDropFilesOnly : $strings.LabelUploaderDragAndDrop }}</p>
|
||||
<p class="text-center text-sm my-5">{{ $strings.MessageOr }}</p>
|
||||
<div class="w-full max-w-xl mx-auto">
|
||||
<div class="flex">
|
||||
<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 class="pt-8 text-center">
|
||||
@@ -48,7 +48,7 @@
|
||||
</p>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,8 +84,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input ref="fileInput" type="file" multiple :accept="inputAccept" class="hidden" @change="inputChanged" />
|
||||
<input ref="fileFolderInput" type="file" webkitdirectory 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" v-if="!isIOS" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -127,6 +127,10 @@ export default {
|
||||
})
|
||||
return extensions
|
||||
},
|
||||
isIOS() {
|
||||
const ua = window.navigator.userAgent
|
||||
return /iPad|iPhone|iPod/.test(ua) && !window.MSStream
|
||||
},
|
||||
streamLibraryItem() {
|
||||
return this.$store.state.streamLibraryItem
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||
timeoutRetry: {
|
||||
maxNumRetry: 4,
|
||||
retryDelayMs: 0,
|
||||
maxRetryDelayMs: 0,
|
||||
maxRetryDelayMs: 0
|
||||
},
|
||||
errorRetry: {
|
||||
maxNumRetry: 8,
|
||||
@@ -160,7 +160,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||
}
|
||||
return retry
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||
|
||||
setDirectPlay() {
|
||||
// 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.loadCurrentTrack()
|
||||
@@ -270,7 +270,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||
// Seeking Direct play
|
||||
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
||||
// 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) {
|
||||
this.startTime = time
|
||||
this.currentTrackIndex = trackIndex
|
||||
@@ -293,7 +293,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||
this.player.volume = volume
|
||||
}
|
||||
|
||||
|
||||
// Utils
|
||||
isValidDuration(duration) {
|
||||
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]
|
||||
return last.end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,6 @@ export default class PlayerHandler {
|
||||
if (listeningTimeToAdd > 20) {
|
||||
syncData = {
|
||||
timeListened: listeningTimeToAdd,
|
||||
duration: this.getDuration(),
|
||||
currentTime: this.getCurrentTime()
|
||||
}
|
||||
}
|
||||
@@ -317,7 +316,6 @@ export default class PlayerHandler {
|
||||
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
|
||||
const syncData = {
|
||||
timeListened: listeningTimeToAdd,
|
||||
duration: this.getDuration(),
|
||||
currentTime
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const SupportedFileTypes = {
|
||||
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'],
|
||||
info: ['nfo'],
|
||||
text: ['txt'],
|
||||
@@ -81,11 +81,9 @@ const Hotkeys = {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Constants
|
||||
}
|
||||
export { Constants }
|
||||
export default ({ app }, inject) => {
|
||||
inject('constants', Constants)
|
||||
inject('keynames', KeyNames)
|
||||
inject('hotkeys', Hotkeys)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ const defaultCode = 'en-us'
|
||||
const languageCodeMap = {
|
||||
bg: { label: 'Български', dateFnsLocale: 'bg' },
|
||||
bn: { label: 'বাংলা', dateFnsLocale: 'bn' },
|
||||
ca: { label: 'Català', dateFnsLocale: 'ca' },
|
||||
cs: { label: 'Čeština', dateFnsLocale: 'cs' },
|
||||
da: { label: 'Dansk', dateFnsLocale: 'da' },
|
||||
de: { label: 'Deutsch', dateFnsLocale: 'de' },
|
||||
@@ -41,6 +42,7 @@ Vue.prototype.$languageCodeOptions = Object.keys(languageCodeMap).map((code) =>
|
||||
|
||||
// iTunes search API uses ISO 3166 country codes: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
||||
const podcastSearchRegionMap = {
|
||||
au: { label: 'Australia' },
|
||||
br: { label: 'Brasil' },
|
||||
be: { label: 'België / Belgique / Belgien' },
|
||||
cz: { label: 'Česko' },
|
||||
@@ -56,6 +58,7 @@ const podcastSearchRegionMap = {
|
||||
hu: { label: 'Magyarország' },
|
||||
nl: { label: 'Nederland' },
|
||||
no: { label: 'Norge' },
|
||||
nz: { label: 'New Zealand' },
|
||||
at: { label: 'Österreich' },
|
||||
pl: { label: 'Polska' },
|
||||
pt: { label: 'Portugal' },
|
||||
|
||||
@@ -98,7 +98,7 @@ export const getters = {
|
||||
const userToken = rootGetters['user/getToken']
|
||||
const lastUpdate = libraryItem.updatedAt || Date.now()
|
||||
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:
|
||||
(state, getters, rootState, rootGetters) =>
|
||||
@@ -106,7 +106,7 @@ export const getters = {
|
||||
const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
||||
if (!libraryItemId) return placeholder
|
||||
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) => {
|
||||
return state.selectedMediaItems.length
|
||||
|
||||
@@ -72,16 +72,17 @@ export const actions = {
|
||||
return this.$axios
|
||||
.$patch('/api/settings', updatePayload)
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
if (result.serverSettings) {
|
||||
commit('setServerSettings', result.serverSettings)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return result
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to update server settings', error)
|
||||
return false
|
||||
const errorMsg = error.response?.data || 'Unknown error'
|
||||
return {
|
||||
error: errorMsg
|
||||
}
|
||||
})
|
||||
},
|
||||
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": "إدارة العلامات"
|
||||
}
|
||||
@@ -629,7 +629,6 @@
|
||||
"MessageItemsSelected": "{0} избрани",
|
||||
"MessageItemsUpdated": "{0} елемента обновени",
|
||||
"MessageJoinUsOn": "Присъединете се към нас",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} слушателски сесии през последната година",
|
||||
"MessageLoading": "Зареждане...",
|
||||
"MessageLoadingFolders": "Зареждане на Папки...",
|
||||
"MessageM4BFailed": "M4B Провалено!",
|
||||
@@ -729,7 +728,6 @@
|
||||
"ToastBookmarkUpdateSuccess": "Отметката е обновена",
|
||||
"ToastChaptersHaveErrors": "Главите имат грешки",
|
||||
"ToastChaptersMustHaveTitles": "Главите трябва да имат заглавия",
|
||||
"ToastCollectionItemsRemoveSuccess": "Елемент(и) премахнати от колекция",
|
||||
"ToastCollectionRemoveSuccess": "Колекцията е премахната",
|
||||
"ToastCollectionUpdateSuccess": "Колекцията е обновена",
|
||||
"ToastItemCoverUpdateSuccess": "Корицата на елемента е обновена",
|
||||
|
||||
+92
-3
@@ -66,6 +66,7 @@
|
||||
"ButtonPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কার করুন",
|
||||
"ButtonQueueAddItem": "সারিতে যোগ করুন",
|
||||
"ButtonQueueRemoveItem": "সারি থেকে মুছে ফেলুন",
|
||||
"ButtonQuickEmbed": "দ্রুত এম্বেড করুন",
|
||||
"ButtonQuickEmbedMetadata": "মেটাডেটা দ্রুত এম্বেড করুন",
|
||||
"ButtonQuickMatch": "দ্রুত ম্যাচ",
|
||||
"ButtonReScan": "পুনরায় স্ক্যান",
|
||||
@@ -87,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "ট্র্যাকলিস্ট সংরক্ষণ করুন",
|
||||
"ButtonScan": "স্ক্যান",
|
||||
"ButtonScanLibrary": "স্ক্যান লাইব্রেরি",
|
||||
"ButtonScrollLeft": "বাম দিকে স্ক্রল করুন",
|
||||
"ButtonScrollRight": "ডানদিকে স্ক্রল করুন",
|
||||
"ButtonSearch": "অনুসন্ধান",
|
||||
"ButtonSelectFolderPath": "ফোল্ডারের পথ নির্বাচন করুন",
|
||||
"ButtonSeries": "সিরিজ",
|
||||
@@ -162,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "বিজ্ঞপ্তি আপডেট করুন",
|
||||
"HeaderNotifications": "বিজ্ঞপ্তি",
|
||||
"HeaderOpenIDConnectAuthentication": "ওপেনআইডি সংযোগ প্রমাণীকরণ",
|
||||
"HeaderOpenListeningSessions": "শোনার সেশন খুলুন",
|
||||
"HeaderOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
||||
"HeaderOtherFiles": "অন্যান্য ফাইল",
|
||||
"HeaderPasswordAuthentication": "পাসওয়ার্ড প্রমাণীকরণ",
|
||||
@@ -179,6 +183,7 @@
|
||||
"HeaderRemoveEpisodes": "{0}টি পর্ব সরান",
|
||||
"HeaderSavedMediaProgress": "মিডিয়া সংরক্ষণের অগ্রগতি",
|
||||
"HeaderSchedule": "সময়সূচী",
|
||||
"HeaderScheduleEpisodeDownloads": "স্বয়ংক্রিয় পর্ব ডাউনলোডের সময়সূচী নির্ধারন করুন",
|
||||
"HeaderScheduleLibraryScans": "স্বয়ংক্রিয় লাইব্রেরি স্ক্যানের সময়সূচী",
|
||||
"HeaderSession": "সেশন",
|
||||
"HeaderSetBackupSchedule": "ব্যাকআপ সময়সূচী সেট করুন",
|
||||
@@ -187,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "পরীক্ষামূলক ফিচার",
|
||||
"HeaderSettingsGeneral": "সাধারণ",
|
||||
"HeaderSettingsScanner": "স্ক্যানার",
|
||||
"HeaderSettingsWebClient": "ওয়েব ক্লায়েন্ট",
|
||||
"HeaderSleepTimer": "স্লিপ টাইমার",
|
||||
"HeaderStatsLargestItems": "সবচেয়ে বড় আইটেম",
|
||||
"HeaderStatsLongestItems": "দীর্ঘতম আইটেম (ঘন্টা)",
|
||||
@@ -224,7 +230,11 @@
|
||||
"LabelAllUsersExcludingGuests": "অতিথি ব্যতীত সকল ব্যবহারকারী",
|
||||
"LabelAllUsersIncludingGuests": "অতিথি সহ সকল ব্যবহারকারী",
|
||||
"LabelAlreadyInYourLibrary": "ইতিমধ্যেই আপনার লাইব্রেরিতে রয়েছে",
|
||||
"LabelApiToken": "API টোকেন",
|
||||
"LabelAppend": "সংযোজন",
|
||||
"LabelAudioBitrate": "অডিও বিটরেট (যেমন- 128k)",
|
||||
"LabelAudioChannels": "অডিও চ্যানেল (১ বা ২)",
|
||||
"LabelAudioCodec": "অডিও কোডেক",
|
||||
"LabelAuthor": "লেখক",
|
||||
"LabelAuthorFirstLast": "লেখক (প্রথম শেষ)",
|
||||
"LabelAuthorLastFirst": "লেখক (শেষ, প্রথম)",
|
||||
@@ -237,6 +247,7 @@
|
||||
"LabelAutoRegister": "স্বয়ংক্রিয় নিবন্ধন",
|
||||
"LabelAutoRegisterDescription": "লগ ইন করার পর স্বয়ংক্রিয়ভাবে নতুন ব্যবহারকারী তৈরি করুন",
|
||||
"LabelBackToUser": "ব্যবহারকারীর কাছে ফিরে যান",
|
||||
"LabelBackupAudioFiles": "অডিও ফাইলগুলো ব্যাকআপ",
|
||||
"LabelBackupLocation": "ব্যাকআপ অবস্থান",
|
||||
"LabelBackupsEnableAutomaticBackups": "স্বয়ংক্রিয় ব্যাকআপ সক্ষম করুন",
|
||||
"LabelBackupsEnableAutomaticBackupsHelp": "ব্যাকআপগুলি /মেটাডাটা/ব্যাকআপে সংরক্ষিত",
|
||||
@@ -245,15 +256,18 @@
|
||||
"LabelBackupsNumberToKeep": "ব্যাকআপের সংখ্যা রাখুন",
|
||||
"LabelBackupsNumberToKeepHelp": "এক সময়ে শুধুমাত্র ১ টি ব্যাকআপ সরানো হবে তাই যদি আপনার কাছে ইতিমধ্যে এর চেয়ে বেশি ব্যাকআপ থাকে তাহলে আপনাকে ম্যানুয়ালি সেগুলি সরিয়ে ফেলতে হবে।",
|
||||
"LabelBitrate": "বিটরেট",
|
||||
"LabelBonus": "উপরিলাভ",
|
||||
"LabelBooks": "বইগুলো",
|
||||
"LabelButtonText": "ঘর পাঠ্য",
|
||||
"LabelByAuthor": "দ্বারা {0}",
|
||||
"LabelChangePassword": "পাসওয়ার্ড পরিবর্তন করুন",
|
||||
"LabelChannels": "চ্যানেল",
|
||||
"LabelChapterCount": "{0} অধ্যায়",
|
||||
"LabelChapterTitle": "অধ্যায়ের শিরোনাম",
|
||||
"LabelChapters": "অধ্যায়",
|
||||
"LabelChaptersFound": "অধ্যায় পাওয়া গেছে",
|
||||
"LabelClickForMoreInfo": "আরো তথ্যের জন্য ক্লিক করুন",
|
||||
"LabelClickToUseCurrentValue": "বর্তমান মান ব্যবহার করতে ক্লিক করুন",
|
||||
"LabelClosePlayer": "প্লেয়ার বন্ধ করুন",
|
||||
"LabelCodec": "কোডেক",
|
||||
"LabelCollapseSeries": "সিরিজ সঙ্কুচিত করুন",
|
||||
@@ -286,6 +300,7 @@
|
||||
"LabelDiscover": "আবিষ্কার",
|
||||
"LabelDownload": "ডাউনলোড করুন",
|
||||
"LabelDownloadNEpisodes": "{0}টি পর্ব ডাউনলোড করুন",
|
||||
"LabelDownloadable": "ডাউনলোডযোগ্য",
|
||||
"LabelDuration": "সময়কাল",
|
||||
"LabelDurationComparisonExactMatch": "(সঠিক মিল)",
|
||||
"LabelDurationComparisonLonger": "({0} দীর্ঘ)",
|
||||
@@ -303,12 +318,25 @@
|
||||
"LabelEmailSettingsTestAddress": "পরীক্ষার ঠিকানা",
|
||||
"LabelEmbeddedCover": "এম্বেডেড কভার",
|
||||
"LabelEnable": "সক্ষম করুন",
|
||||
"LabelEncodingBackupLocation": "আপনার আসল অডিও ফাইলগুলোর একটি ব্যাকআপ এখানে সংরক্ষণ করা হবে:",
|
||||
"LabelEncodingChaptersNotEmbedded": "মাল্টি-ট্র্যাক অডিওবুকগুলোতে অধ্যায় এম্বেড করা হয় না।",
|
||||
"LabelEncodingClearItemCache": "পর্যায়ক্রমে আইটেম ক্যাশে পরিষ্কার করতে ভুলবেন না।",
|
||||
"LabelEncodingFinishedM4B": "সমাপ্ত হওয়া M4B-গুলো আপনার অডিওবুক ফোল্ডারে এখানে রাখা হবে:",
|
||||
"LabelEncodingInfoEmbedded": "আপনার অডিওবুক ফোল্ডারের ভিতরে অডিও ট্র্যাকগুলোতে মেটাডেটা এমবেড করা হবে।",
|
||||
"LabelEncodingStartedNavigation": "একবার টাস্ক শুরু হলে আপনি এই পৃষ্ঠা থেকে অন্যত্র যেতে পারেন।",
|
||||
"LabelEncodingTimeWarning": "এনকোডিং ৩০ মিনিট পর্যন্ত সময় নিতে পারে।",
|
||||
"LabelEncodingWarningAdvancedSettings": "সতর্কতা: এই সেটিংস আপডেট করবেন না, যদি না আপনি ffmpeg এনকোডিং বিকল্পগুলোর সাথে পরিচিত হন।",
|
||||
"LabelEncodingWatcherDisabled": "আপনার যদি পর্যবেক্ষক অক্ষম থাকে তবে আপনাকে পরে এই অডিওবুকটি পুনরায় স্ক্যান করতে হবে।",
|
||||
"LabelEnd": "সমাপ্ত",
|
||||
"LabelEndOfChapter": "অধ্যায়ের সমাপ্তি",
|
||||
"LabelEpisode": "পর্ব",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "পর্বটি আরএসএস ফিডের সাথে সংযুক্ত করা হয়নি",
|
||||
"LabelEpisodeNumber": "পর্ব #{0}",
|
||||
"LabelEpisodeTitle": "পর্বের শিরোনাম",
|
||||
"LabelEpisodeType": "পর্বের ধরন",
|
||||
"LabelEpisodeUrlFromRssFeed": "আরএসএস ফিড থেকে পর্ব URL",
|
||||
"LabelEpisodes": "পর্বগুলো",
|
||||
"LabelEpisodic": "প্রাসঙ্গিক",
|
||||
"LabelExample": "উদাহরণ",
|
||||
"LabelExpandSeries": "সিরিজ প্রসারিত করুন",
|
||||
"LabelExpandSubSeries": "সাব সিরিজ প্রসারিত করুন",
|
||||
@@ -336,6 +364,7 @@
|
||||
"LabelFontScale": "ফন্ট স্কেল",
|
||||
"LabelFontStrikethrough": "অবচ্ছেদন রেখা",
|
||||
"LabelFormat": "ফরম্যাট",
|
||||
"LabelFull": "পূর্ণ",
|
||||
"LabelGenre": "ঘরানা",
|
||||
"LabelGenres": "ঘরানাগুলো",
|
||||
"LabelHardDeleteFile": "জোরপূর্বক ফাইল মুছে ফেলুন",
|
||||
@@ -391,6 +420,10 @@
|
||||
"LabelLowestPriority": "সর্বনিম্ন অগ্রাধিকার",
|
||||
"LabelMatchExistingUsersBy": "বিদ্যমান ব্যবহারকারীদের দ্বারা মিলিত করুন",
|
||||
"LabelMatchExistingUsersByDescription": "বিদ্যমান ব্যবহারকারীদের সংযোগ করার জন্য ব্যবহৃত হয়। একবার সংযুক্ত হলে, ব্যবহারকারীদের আপনার SSO প্রদানকারীর থেকে একটি অনন্য আইডি দ্বারা মিলিত হবে",
|
||||
"LabelMaxEpisodesToDownload": "সর্বাধিক # টি পর্ব ডাউনলোড করা হবে। অসীমের জন্য 0 ব্যবহার করুন।",
|
||||
"LabelMaxEpisodesToDownloadPerCheck": "প্রতি কিস্তিতে সর্বাধিক # টি নতুন পর্ব ডাউনলোড করা হবে",
|
||||
"LabelMaxEpisodesToKeep": "সর্বোচ্চ # টি পর্ব রাখা হবে",
|
||||
"LabelMaxEpisodesToKeepHelp": "০ কোন সর্বোচ্চ সীমা সেট করে না। একটি নতুন পর্ব স্বয়ংক্রিয়-ডাউনলোড হওয়ার পরে আপনার যদি X-এর বেশি পর্ব থাকে তবে এটি সবচেয়ে পুরানো পর্বটি মুছে ফেলবে। এটি প্রতি নতুন ডাউনলোডের জন্য শুধুমাত্র ১ টি পর্ব মুছে ফেলবে।",
|
||||
"LabelMediaPlayer": "মিডিয়া প্লেয়ার",
|
||||
"LabelMediaType": "মিডিয়ার ধরন",
|
||||
"LabelMetaTag": "মেটা ট্যাগ",
|
||||
@@ -436,12 +469,14 @@
|
||||
"LabelOpenIDGroupClaimDescription": "ওপেনআইডি দাবির নাম যাতে ব্যবহারকারীর গোষ্ঠীর একটি তালিকা থাকে। সাধারণত <code>গ্রুপ</code> হিসাবে উল্লেখ করা হয়। <b>কনফিগার করা থাকলে</b>, অ্যাপ্লিকেশনটি স্বয়ংক্রিয়ভাবে এর উপর ভিত্তি করে ব্যবহারকারীর গোষ্ঠীর সদস্যপদ নির্ধারণ করবে, শর্ত এই যে এই গোষ্ঠীগুলি কেস-অসংবেদনশীলভাবে দাবিতে 'অ্যাডমিন', 'ব্যবহারকারী' বা 'অতিথি' নাম দেওয়া হয়৷ দাবিতে একটি তালিকা থাকা উচিত এবং যদি একজন ব্যবহারকারী একাধিক গোষ্ঠীর অন্তর্গত হয় তবে অ্যাপ্লিকেশনটি বরাদ্দ করবে সর্বোচ্চ স্তরের অ্যাক্সেসের সাথে সঙ্গতিপূর্ণ ভূমিকা৷ যদি কোনও গোষ্ঠীর সাথে মেলে না, তবে অ্যাক্সেস অস্বীকার করা হবে।",
|
||||
"LabelOpenRSSFeed": "আরএসএস ফিড খুলুন",
|
||||
"LabelOverwrite": "পুনঃলিখিত",
|
||||
"LabelPaginationPageXOfY": "{1} টির মধ্যে {0} পৃষ্ঠা",
|
||||
"LabelPassword": "পাসওয়ার্ড",
|
||||
"LabelPath": "পথ",
|
||||
"LabelPermanent": "স্থায়ী",
|
||||
"LabelPermissionsAccessAllLibraries": "সমস্ত লাইব্রেরি অ্যাক্সেস করতে পারবে",
|
||||
"LabelPermissionsAccessAllTags": "সমস্ত ট্যাগ অ্যাক্সেস করতে পারবে",
|
||||
"LabelPermissionsAccessExplicitContent": "স্পষ্ট বিষয়বস্তু অ্যাক্সেস করতে পারে",
|
||||
"LabelPermissionsCreateEreader": "ইরিডার তৈরি করতে পারেন",
|
||||
"LabelPermissionsDelete": "মুছে দিতে পারবে",
|
||||
"LabelPermissionsDownload": "ডাউনলোড করতে পারবে",
|
||||
"LabelPermissionsUpdate": "আপডেট করতে পারবে",
|
||||
@@ -465,6 +500,8 @@
|
||||
"LabelPubDate": "প্রকাশের তারিখ",
|
||||
"LabelPublishYear": "প্রকাশের বছর",
|
||||
"LabelPublishedDate": "প্রকাশিত {0}",
|
||||
"LabelPublishedDecade": "প্রকাশনার দশক",
|
||||
"LabelPublishedDecades": "প্রকাশনার দশকগুলো",
|
||||
"LabelPublisher": "প্রকাশক",
|
||||
"LabelPublishers": "প্রকাশকরা",
|
||||
"LabelRSSFeedCustomOwnerEmail": "কাস্টম মালিকের ইমেইল",
|
||||
@@ -484,24 +521,32 @@
|
||||
"LabelRedo": "পুনরায় করুন",
|
||||
"LabelRegion": "অঞ্চল",
|
||||
"LabelReleaseDate": "উন্মোচনের তারিখ",
|
||||
"LabelRemoveAllMetadataAbs": "সমস্ত metadata.abs ফাইল সরান",
|
||||
"LabelRemoveAllMetadataJson": "সমস্ত metadata.json ফাইল সরান",
|
||||
"LabelRemoveCover": "কভার সরান",
|
||||
"LabelRemoveMetadataFile": "লাইব্রেরি আইটেম ফোল্ডারে মেটাডেটা ফাইল সরান",
|
||||
"LabelRemoveMetadataFileHelp": "আপনার {0} ফোল্ডারের সমস্ত metadata.json এবং metadata.abs ফাইলগুলি সরান।",
|
||||
"LabelRowsPerPage": "প্রতি পৃষ্ঠায় সারি",
|
||||
"LabelSearchTerm": "অনুসন্ধান শব্দ",
|
||||
"LabelSearchTitle": "অনুসন্ধান শিরোনাম",
|
||||
"LabelSearchTitleOrASIN": "অনুসন্ধান শিরোনাম বা ASIN",
|
||||
"LabelSeason": "সেশন",
|
||||
"LabelSeasonNumber": "মরসুম #{0}",
|
||||
"LabelSelectAll": "সব নির্বাচন করুন",
|
||||
"LabelSelectAllEpisodes": "সমস্ত পর্ব নির্বাচন করুন",
|
||||
"LabelSelectEpisodesShowing": "দেখানো {0}টি পর্ব নির্বাচন করুন",
|
||||
"LabelSelectUsers": "ব্যবহারকারী নির্বাচন করুন",
|
||||
"LabelSendEbookToDevice": "ই-বই পাঠান...",
|
||||
"LabelSequence": "ক্রম",
|
||||
"LabelSerial": "ধারাবাহিক",
|
||||
"LabelSeries": "সিরিজ",
|
||||
"LabelSeriesName": "সিরিজের নাম",
|
||||
"LabelSeriesProgress": "সিরিজের অগ্রগতি",
|
||||
"LabelServerLogLevel": "সার্ভার লগ লেভেল",
|
||||
"LabelServerYearReview": "সার্ভারের বাৎসরিক পর্যালোচনা ({0})",
|
||||
"LabelSetEbookAsPrimary": "প্রাথমিক হিসাবে সেট করুন",
|
||||
"LabelSetEbookAsSupplementary": "পরিপূরক হিসেবে সেট করুন",
|
||||
"LabelSettingsAllowIframe": "আইফ্রেমে এম্বেড করার অনুমতি দিন",
|
||||
"LabelSettingsAudiobooksOnly": "শুধুমাত্র অডিও বই",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "এই সেটিংটি সক্ষম করা ই-বই ফাইলগুলিকে উপেক্ষা করবে যদি না সেগুলি একটি অডিওবই ফোল্ডারের মধ্যে থাকে যে ক্ষেত্রে সেগুলিকে সম্পূরক ই-বই হিসাবে সেট করা হবে",
|
||||
"LabelSettingsBookshelfViewHelp": "কাঠের তাক সহ স্কুমরফিক ডিজাইন",
|
||||
@@ -523,6 +568,9 @@
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "যে সিরিজগুলোতে একটি বই আছে সেগুলো সিরিজের পাতা এবং নীড় পেজের তাক থেকে লুকিয়ে রাখা হবে।",
|
||||
"LabelSettingsHomePageBookshelfView": "নীড় পেজে বুকশেলফ ভিউ ব্যবহার করুন",
|
||||
"LabelSettingsLibraryBookshelfView": "লাইব্রেরি বুকশেলফ ভিউ ব্যবহার করুন",
|
||||
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "শতকরা সম্পূর্ণ এর চেয়ে বেশি",
|
||||
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "বাকি সময় (সেকেন্ড) এর চেয়ে কম",
|
||||
"LabelSettingsLibraryMarkAsFinishedWhen": "মিডিয়া আইটেমকে সমাপ্ত হিসাবে চিহ্নিত করুন যখন",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "কন্টিনিউ সিরিজে আগের বইগুলো এড়িয়ে যান",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "কন্টিনিউ সিরিজের নীড় পেজ শেল্ফ দেখায় যে সিরিজে শুরু হয়নি এমন প্রথম বই যার অন্তত একটি বই শেষ হয়েছে এবং কোনো বই চলছে না। এই সেটিংটি সক্ষম করলে শুরু না হওয়া প্রথম বইটির পরিবর্তে সবচেয়ে দূরের সম্পূর্ণ বই থেকে সিরিজ চলতে থাকবে।",
|
||||
"LabelSettingsParseSubtitles": "সাবটাইটেল পার্স করুন",
|
||||
@@ -541,6 +589,7 @@
|
||||
"LabelSettingsStoreMetadataWithItemHelp": "ডিফল্টরূপে মেটাডেটা ফাইলগুলি /মেটাডাটা/আইটেমগুলি -এ সংরক্ষণ করা হয়, এই সেটিংটি সক্ষম করলে মেটাডেটা ফাইলগুলি আপনার লাইব্রেরি আইটেম ফোল্ডারে সংরক্ষণ করা হবে",
|
||||
"LabelSettingsTimeFormat": "সময় বিন্যাস",
|
||||
"LabelShare": "শেয়ার করুন",
|
||||
"LabelShareDownloadableHelp": "শেয়ার লিঙ্ক সহ ব্যবহারকারীদের লাইব্রেরি আইটেমের একটি জিপ ফাইল ডাউনলোড করার অনুমতি দিন।",
|
||||
"LabelShareOpen": "শেয়ার খোলা",
|
||||
"LabelShareURL": "শেয়ার ইউআরএল",
|
||||
"LabelShowAll": "সব দেখান",
|
||||
@@ -549,6 +598,8 @@
|
||||
"LabelSize": "আকার",
|
||||
"LabelSleepTimer": "স্লিপ টাইমার",
|
||||
"LabelSlug": "স্লাগ",
|
||||
"LabelSortAscending": "আরোহী",
|
||||
"LabelSortDescending": "অবরোহী",
|
||||
"LabelStart": "শুরু",
|
||||
"LabelStartTime": "শুরুর সময়",
|
||||
"LabelStarted": "শুরু হয়েছে",
|
||||
@@ -587,6 +638,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} মিনিট",
|
||||
"LabelTimeDurationXSeconds": "{0} সেকেন্ড",
|
||||
"LabelTimeInMinutes": "মিনিটে সময়",
|
||||
"LabelTimeLeft": "{0} বাকি",
|
||||
"LabelTimeListened": "সময় শোনা হয়েছে",
|
||||
"LabelTimeListenedToday": "আজ শোনার সময়",
|
||||
"LabelTimeRemaining": "{0}টি অবশিষ্ট",
|
||||
@@ -594,6 +646,7 @@
|
||||
"LabelTitle": "শিরোনাম",
|
||||
"LabelToolsEmbedMetadata": "মেটাডেটা এম্বেড করুন",
|
||||
"LabelToolsEmbedMetadataDescription": "কভার ইমেজ এবং অধ্যায় সহ অডিও ফাইলগুলিতে মেটাডেটা এম্বেড করুন।",
|
||||
"LabelToolsM4bEncoder": "M4B এনকোডার",
|
||||
"LabelToolsMakeM4b": "M4B অডিওবুক ফাইল তৈরি করুন",
|
||||
"LabelToolsMakeM4bDescription": "এমবেডেড মেটাডেটা, কভার ইমেজ এবং অধ্যায় সহ একটি .M4B অডিওবুক ফাইল তৈরি করুন।",
|
||||
"LabelToolsSplitM4b": "M4B কে MP3 তে বিভক্ত করুন",
|
||||
@@ -606,6 +659,7 @@
|
||||
"LabelTracksMultiTrack": "মাল্টি-ট্র্যাক",
|
||||
"LabelTracksNone": "কোন ট্র্যাক নেই",
|
||||
"LabelTracksSingleTrack": "একক-ট্র্যাক",
|
||||
"LabelTrailer": "আনুগমিক",
|
||||
"LabelType": "টাইপ",
|
||||
"LabelUnabridged": "অসংলগ্ন",
|
||||
"LabelUndo": "পূর্বাবস্থা",
|
||||
@@ -617,10 +671,13 @@
|
||||
"LabelUpdateDetailsHelp": "একটি মিল থাকা অবস্থায় নির্বাচিত বইগুলির বিদ্যমান বিবরণ ওভাররাইট করার অনুমতি দিন",
|
||||
"LabelUpdatedAt": "আপডেট করা হয়েছে",
|
||||
"LabelUploaderDragAndDrop": "ফাইল বা ফোল্ডার টেনে আনুন এবং ফেলে দিন",
|
||||
"LabelUploaderDragAndDropFilesOnly": "ফাইল টেনে আনুন",
|
||||
"LabelUploaderDropFiles": "ফাইলগুলো ফেলে দিন",
|
||||
"LabelUploaderItemFetchMetadataHelp": "স্বয়ংক্রিয়ভাবে শিরোনাম, লেখক এবং সিরিজ আনুন",
|
||||
"LabelUseAdvancedOptions": "উন্নত বিকল্প ব্যবহার করুন",
|
||||
"LabelUseChapterTrack": "অধ্যায় ট্র্যাক ব্যবহার করুন",
|
||||
"LabelUseFullTrack": "সম্পূর্ণ ট্র্যাক ব্যবহার করুন",
|
||||
"LabelUseZeroForUnlimited": "অসীমের জন্য 0 ব্যবহার করুন",
|
||||
"LabelUser": "ব্যবহারকারী",
|
||||
"LabelUsername": "ব্যবহারকারীর নাম",
|
||||
"LabelValue": "মান",
|
||||
@@ -630,6 +687,8 @@
|
||||
"LabelViewPlayerSettings": "প্লেয়ার সেটিংস দেখুন",
|
||||
"LabelViewQueue": "প্লেয়ার সারি দেখুন",
|
||||
"LabelVolume": "ভলিউম",
|
||||
"LabelWebRedirectURLsDescription": "লগইন করার পরে ওয়েব অ্যাপে পুনঃনির্দেশের অনুমতি দেওয়ার জন্য আপনার OAuth প্রদানকারীতে এই URLগুলোকে অনুমোদন করুন:",
|
||||
"LabelWebRedirectURLsSubfolder": "রিডাইরেক্ট URL এর জন্য সাবফোল্ডার",
|
||||
"LabelWeekdaysToRun": "চলতে হবে সপ্তাহের দিন",
|
||||
"LabelXBooks": "{0}টি বই",
|
||||
"LabelXItems": "{0}টি আইটেম",
|
||||
@@ -667,6 +726,7 @@
|
||||
"MessageConfirmDeleteMetadataProvider": "আপনি কি নিশ্চিতভাবে কাস্টম মেটাডেটা প্রদানকারী \"{0}\" মুছতে চান?",
|
||||
"MessageConfirmDeleteNotification": "আপনি কি নিশ্চিতভাবে এই বিজ্ঞপ্তিটি মুছতে চান?",
|
||||
"MessageConfirmDeleteSession": "আপনি কি নিশ্চিত আপনি এই অধিবেশন মুছে দিতে চান?",
|
||||
"MessageConfirmEmbedMetadataInAudioFiles": "আপনি কি {0}টি অডিও ফাইলে মেটাডেটা এম্বেড করার বিষয়ে নিশ্চিত?",
|
||||
"MessageConfirmForceReScan": "আপনি কি নিশ্চিত যে আপনি জোর করে পুনরায় স্ক্যান করতে চান?",
|
||||
"MessageConfirmMarkAllEpisodesFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্ব সমাপ্ত হিসাবে চিহ্নিত করতে চান?",
|
||||
"MessageConfirmMarkAllEpisodesNotFinished": "আপনি কি নিশ্চিত যে আপনি সমস্ত পর্বকে শেষ হয়নি বলে চিহ্নিত করতে চান?",
|
||||
@@ -678,6 +738,7 @@
|
||||
"MessageConfirmPurgeCache": "ক্যাশে পরিষ্কারক <code>/metadata/cache</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে। <br /><br />আপনি কি নিশ্চিত আপনি ক্যাশে ডিরেক্টরি সরাতে চান?",
|
||||
"MessageConfirmPurgeItemsCache": "আইটেম ক্যাশে পরিষ্কারক <code>/metadata/cache/items</code>-এ সম্পূর্ণ ডিরেক্টরি মুছে ফেলবে।<br />আপনি কি নিশ্চিত?",
|
||||
"MessageConfirmQuickEmbed": "সতর্কতা! দ্রুত এম্বেড আপনার অডিও ফাইলের ব্যাকআপ করবে না। নিশ্চিত করুন যে আপনার অডিও ফাইলগুলির একটি ব্যাকআপ আছে। <br><br>আপনি কি চালিয়ে যেতে চান?",
|
||||
"MessageConfirmQuickMatchEpisodes": "একটি মিল পাওয়া গেলে দ্রুত ম্যাচিং পর্বগুলি বিস্তারিত ওভাররাইট করবে। শুধুমাত্র অতুলনীয় পর্ব আপডেট করা হবে। আপনি কি নিশ্চিত?",
|
||||
"MessageConfirmReScanLibraryItems": "আপনি কি নিশ্চিত যে আপনি {0}টি আইটেম পুনরায় স্ক্যান করতে চান?",
|
||||
"MessageConfirmRemoveAllChapters": "আপনি কি নিশ্চিত যে আপনি সমস্ত অধ্যায় সরাতে চান?",
|
||||
"MessageConfirmRemoveAuthor": "আপনি কি নিশ্চিত যে আপনি লেখক \"{0}\" অপসারণ করতে চান?",
|
||||
@@ -685,6 +746,7 @@
|
||||
"MessageConfirmRemoveEpisode": "আপনি কি নিশ্চিত আপনি \"{0}\" পর্বটি সরাতে চান?",
|
||||
"MessageConfirmRemoveEpisodes": "আপনি কি নিশ্চিত যে আপনি {0}টি পর্ব সরাতে চান?",
|
||||
"MessageConfirmRemoveListeningSessions": "আপনি কি নিশ্চিত যে আপনি {0}টি শোনার সেশন সরাতে চান?",
|
||||
"MessageConfirmRemoveMetadataFiles": "আপনি কি আপনার লাইব্রেরি আইটেম ফোল্ডারে থাকা সমস্ত মেটাডেটা {0} ফাইল মুছে ফেলার বিষয়ে নিশ্চিত?",
|
||||
"MessageConfirmRemoveNarrator": "আপনি কি \"{0}\" বর্ণনাকারীকে সরানোর বিষয়ে নিশ্চিত?",
|
||||
"MessageConfirmRemovePlaylist": "আপনি কি নিশ্চিত যে আপনি আপনার প্লেলিস্ট \"{0}\" সরাতে চান?",
|
||||
"MessageConfirmRenameGenre": "আপনি কি নিশ্চিত যে আপনি সমস্ত আইটেমের জন্য \"{0}\" ধারার নাম পরিবর্তন করে \"{1}\" করতে চান?",
|
||||
@@ -700,6 +762,7 @@
|
||||
"MessageDragFilesIntoTrackOrder": "সঠিক ট্র্যাক অর্ডারে ফাইল টেনে আনুন",
|
||||
"MessageEmbedFailed": "এম্বেড ব্যর্থ হয়েছে!",
|
||||
"MessageEmbedFinished": "এম্বেড করা শেষ!",
|
||||
"MessageEmbedQueue": "মেটাডেটা এম্বেডের জন্য সারিবদ্ধ ({0} সারিতে)",
|
||||
"MessageEpisodesQueuedForDownload": "{0} পর্ব(গুলি) ডাউনলোডের জন্য সারিবদ্ধ",
|
||||
"MessageEreaderDevices": "ই-বুক সরবরাহ নিশ্চিত করতে, আপনাকে নীচে তালিকাভুক্ত প্রতিটি ডিভাইসের জন্য একটি বৈধ প্রেরক হিসাবে উপরের ইমেল ঠিকানাটি যুক্ত করতে হতে পারে।",
|
||||
"MessageFeedURLWillBe": "ফিড URL হবে {0}",
|
||||
@@ -710,7 +773,6 @@
|
||||
"MessageItemsSelected": "{0}টি আইটেম নির্বাচিত",
|
||||
"MessageItemsUpdated": "{0}টি আইটেম আপডেট করা হয়েছে",
|
||||
"MessageJoinUsOn": "আমাদের সাথে যোগ দিন",
|
||||
"MessageListeningSessionsInTheLastYear": "গত বছরে {0}টি শোনার সেশন",
|
||||
"MessageLoading": "লোড হচ্ছে.।",
|
||||
"MessageLoadingFolders": "ফোল্ডার লোড হচ্ছে...",
|
||||
"MessageLogsDescription": "লগগুলি JSON ফাইল হিসাবে <code>/metadata/logs</code>-এ সংরক্ষণ করা হয়। ক্র্যাশ লগগুলি <code>/metadata/logs/crash_logs.txt</code>-এ সংরক্ষণ করা হয়।",
|
||||
@@ -744,6 +806,7 @@
|
||||
"MessageNoLogs": "কোনও লগ নেই",
|
||||
"MessageNoMediaProgress": "মিডিয়া অগ্রগতি নেই",
|
||||
"MessageNoNotifications": "কোনো বিজ্ঞপ্তি নেই",
|
||||
"MessageNoPodcastFeed": "অবৈধ পডকাস্ট: কোনো ফিড নেই",
|
||||
"MessageNoPodcastsFound": "কোন পডকাস্ট পাওয়া যায়নি",
|
||||
"MessageNoResults": "কোন ফলাফল নেই",
|
||||
"MessageNoSearchResultsFor": "\"{0}\" এর জন্য কোন অনুসন্ধান ফলাফল নেই",
|
||||
@@ -760,6 +823,10 @@
|
||||
"MessagePlaylistCreateFromCollection": "সংগ্রহ থেকে প্লেলিস্ট তৈরি করুন",
|
||||
"MessagePleaseWait": "অনুগ্রহ করে অপেক্ষা করুন..।",
|
||||
"MessagePodcastHasNoRSSFeedForMatching": "পডকাস্টের সাথে মিলের জন্য ব্যবহার করার জন্য কোন RSS ফিড ইউআরএল নেই",
|
||||
"MessagePodcastSearchField": "অনুসন্ধান শব্দ বা RSS ফিড URL লিখুন",
|
||||
"MessageQuickEmbedInProgress": "দ্রুত এম্বেড করা হচ্ছে",
|
||||
"MessageQuickEmbedQueue": "দ্রুত এম্বেড করার জন্য সারিবদ্ধ ({0} সারিতে)",
|
||||
"MessageQuickMatchAllEpisodes": "দ্রুত ম্যাচ সব পর্ব",
|
||||
"MessageQuickMatchDescription": "খালি আইটেমের বিশদ বিবরণ এবং '{0}' থেকে প্রথম ম্যাচের ফলাফলের সাথে কভার করুন। সার্ভার সেটিং সক্ষম না থাকলে বিশদ ওভাররাইট করে না।",
|
||||
"MessageRemoveChapter": "অধ্যায় সরান",
|
||||
"MessageRemoveEpisodes": "{0}টি পর্ব(গুলি) সরান",
|
||||
@@ -802,6 +869,9 @@
|
||||
"MessageTaskOpmlImportFeedPodcastExists": "পডকাস্ট আগে থেকেই পাথে বিদ্যমান",
|
||||
"MessageTaskOpmlImportFeedPodcastFailed": "পডকাস্ট তৈরি করতে ব্যর্থ",
|
||||
"MessageTaskOpmlImportFinished": "{0}টি পডকাস্ট যোগ করা হয়েছে",
|
||||
"MessageTaskOpmlParseFailed": "OPML ফাইল পার্স করতে ব্যর্থ হয়েছে",
|
||||
"MessageTaskOpmlParseFastFail": "অবৈধ OPML ফাইল <opml> ট্যাগ পাওয়া যায়নি বা একটি <outline> ট্যাগ পাওয়া যায়নি",
|
||||
"MessageTaskOpmlParseNoneFound": "OPML ফাইলে কোনো ফিড পাওয়া যায়নি",
|
||||
"MessageTaskScanItemsAdded": "{0}টি করা হয়েছে",
|
||||
"MessageTaskScanItemsMissing": "{0}টি অনুপস্থিত",
|
||||
"MessageTaskScanItemsUpdated": "{0} টি আপডেট করা হয়েছে",
|
||||
@@ -826,6 +896,10 @@
|
||||
"NoteUploaderFoldersWithMediaFiles": "মিডিয়া ফাইল সহ ফোল্ডারগুলি আলাদা লাইব্রেরি আইটেম হিসাবে পরিচালনা করা হবে।",
|
||||
"NoteUploaderOnlyAudioFiles": "যদি শুধুমাত্র অডিও ফাইল আপলোড করা হয় তবে প্রতিটি অডিও ফাইল একটি পৃথক অডিওবুক হিসাবে পরিচালনা করা হবে।",
|
||||
"NoteUploaderUnsupportedFiles": "অসমর্থিত ফাইলগুলি উপেক্ষা করা হয়। একটি ফোল্ডার বেছে নেওয়া বা ফেলে দেওয়ার সময়, আইটেম ফোল্ডারে নেই এমন অন্যান্য ফাইলগুলি উপেক্ষা করা হয়।",
|
||||
"NotificationOnBackupCompletedDescription": "ব্যাকআপ সম্পূর্ণ হলে ট্রিগার হবে",
|
||||
"NotificationOnBackupFailedDescription": "ব্যাকআপ ব্যর্থ হলে ট্রিগার হবে",
|
||||
"NotificationOnEpisodeDownloadedDescription": "একটি পডকাস্ট পর্ব স্বয়ংক্রিয়ভাবে ডাউনলোড হলে ট্রিগার হবে",
|
||||
"NotificationOnTestDescription": "বিজ্ঞপ্তি সিস্টেম পরীক্ষার জন্য ইভেন্ট",
|
||||
"PlaceholderNewCollection": "নতুন সংগ্রহের নাম",
|
||||
"PlaceholderNewFolderPath": "নতুন ফোল্ডার পথ",
|
||||
"PlaceholderNewPlaylist": "নতুন প্লেলিস্টের নাম",
|
||||
@@ -851,6 +925,7 @@
|
||||
"StatsYearInReview": "বাৎসরিক পর্যালোচনা",
|
||||
"ToastAccountUpdateSuccess": "অ্যাকাউন্ট আপডেট করা হয়েছে",
|
||||
"ToastAppriseUrlRequired": "একটি Apprise ইউআরএল লিখতে হবে",
|
||||
"ToastAsinRequired": "ASIN প্রয়োজন",
|
||||
"ToastAuthorImageRemoveSuccess": "লেখকের ছবি সরানো হয়েছে",
|
||||
"ToastAuthorNotFound": "লেখক \"{0}\" খুঁজে পাওয়া যায়নি",
|
||||
"ToastAuthorRemoveSuccess": "লেখক সরানো হয়েছে",
|
||||
@@ -870,6 +945,8 @@
|
||||
"ToastBackupUploadSuccess": "ব্যাকআপ আপলোড হয়েছে",
|
||||
"ToastBatchDeleteFailed": "ব্যাচ মুছে ফেলতে ব্যর্থ হয়েছে",
|
||||
"ToastBatchDeleteSuccess": "ব্যাচ মুছে ফেলা সফল হয়েছে",
|
||||
"ToastBatchQuickMatchFailed": "ব্যাচ কুইক ম্যাচ ব্যর্থ!",
|
||||
"ToastBatchQuickMatchStarted": "{0}টি বইয়ের ব্যাচ কুইক ম্যাচ শুরু হয়েছে!",
|
||||
"ToastBatchUpdateFailed": "ব্যাচ আপডেট ব্যর্থ হয়েছে",
|
||||
"ToastBatchUpdateSuccess": "ব্যাচ আপডেট সাফল্য",
|
||||
"ToastBookmarkCreateFailed": "বুকমার্ক তৈরি করতে ব্যর্থ",
|
||||
@@ -881,9 +958,8 @@
|
||||
"ToastChaptersHaveErrors": "অধ্যায়ে ত্রুটি আছে",
|
||||
"ToastChaptersMustHaveTitles": "অধ্যায়ের শিরোনাম থাকতে হবে",
|
||||
"ToastChaptersRemoved": "অধ্যায়গুলো মুছে ফেলা হয়েছে",
|
||||
"ToastChaptersUpdated": "অধ্যায় আপডেট করা হয়েছে",
|
||||
"ToastCollectionItemsAddFailed": "আইটেম(গুলি) সংগ্রহে যোগ করা ব্যর্থ হয়েছে",
|
||||
"ToastCollectionItemsAddSuccess": "আইটেম(গুলি) সংগ্রহে যোগ করা সফল হয়েছে",
|
||||
"ToastCollectionItemsRemoveSuccess": "আইটেম(গুলি) সংগ্রহ থেকে সরানো হয়েছে",
|
||||
"ToastCollectionRemoveSuccess": "সংগ্রহ সরানো হয়েছে",
|
||||
"ToastCollectionUpdateSuccess": "সংগ্রহ আপডেট করা হয়েছে",
|
||||
"ToastCoverUpdateFailed": "কভার আপডেট ব্যর্থ হয়েছে",
|
||||
@@ -898,11 +974,14 @@
|
||||
"ToastEncodeCancelSucces": "এনকোড বাতিল করা হয়েছে",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "সারি সাফ করতে ব্যর্থ হয়েছে",
|
||||
"ToastEpisodeDownloadQueueClearSuccess": "পর্ব ডাউনলোড সারি পরিষ্কার করা হয়েছে",
|
||||
"ToastEpisodeUpdateSuccess": "{0}টি পর্ব আপডেট করা হয়েছে",
|
||||
"ToastErrorCannotShare": "এই ডিভাইসে স্থানীয়ভাবে শেয়ার করা যাবে না",
|
||||
"ToastFailedToLoadData": "ডেটা লোড করা যায়নি",
|
||||
"ToastFailedToMatch": "মেলাতে ব্যর্থ হয়েছে",
|
||||
"ToastFailedToShare": "শেয়ার করতে ব্যর্থ",
|
||||
"ToastFailedToUpdate": "আপডেট করতে ব্যর্থ হয়েছে",
|
||||
"ToastInvalidImageUrl": "অকার্যকর ছবির ইউআরএল",
|
||||
"ToastInvalidMaxEpisodesToDownload": "ডাউনলোড করার জন্য অবৈধ সর্বোচ্চ পর্ব",
|
||||
"ToastInvalidUrl": "অকার্যকর ইউআরএল",
|
||||
"ToastItemCoverUpdateSuccess": "আইটেম কভার আপডেট করা হয়েছে",
|
||||
"ToastItemDeletedFailed": "আইটেম মুছে ফেলতে ব্যর্থ",
|
||||
@@ -920,14 +999,22 @@
|
||||
"ToastLibraryScanFailedToStart": "স্ক্যান শুরু করতে ব্যর্থ",
|
||||
"ToastLibraryScanStarted": "লাইব্রেরি স্ক্যান শুরু হয়েছে",
|
||||
"ToastLibraryUpdateSuccess": "লাইব্রেরি \"{0}\" আপডেট করা হয়েছে",
|
||||
"ToastMatchAllAuthorsFailed": "সমস্ত লেখকের সাথে মিলতে ব্যর্থ হয়েছে",
|
||||
"ToastMetadataFilesRemovedError": "মেটাডেটা সরানোর সময় ত্রুটি {0} ফাইল",
|
||||
"ToastMetadataFilesRemovedNoneFound": "কোনো মেটাডেটা নেই।লাইব্রেরিতে {0} ফাইল পাওয়া গেছে",
|
||||
"ToastMetadataFilesRemovedNoneRemoved": "কোনো মেটাডেটা নেই।{0} ফাইল সরানো হয়েছে",
|
||||
"ToastMetadataFilesRemovedSuccess": "{0} মেটাডেটা৷{1} ফাইল সরানো হয়েছে",
|
||||
"ToastMustHaveAtLeastOnePath": "অন্তত একটি পথ থাকতে হবে",
|
||||
"ToastNameEmailRequired": "নাম এবং ইমেইল আবশ্যক",
|
||||
"ToastNameRequired": "নাম আবশ্যক",
|
||||
"ToastNewEpisodesFound": "{0}টি নতুন পর্ব পাওয়া গেছে",
|
||||
"ToastNewUserCreatedFailed": "অ্যাকাউন্ট তৈরি করতে ব্যর্থ: \"{0}\"",
|
||||
"ToastNewUserCreatedSuccess": "নতুন একাউন্ট তৈরি হয়েছে",
|
||||
"ToastNewUserLibraryError": "অন্তত একটি লাইব্রেরি নির্বাচন করতে হবে",
|
||||
"ToastNewUserPasswordError": "অন্তত একটি পাসওয়ার্ড থাকতে হবে, শুধুমাত্র রুট ব্যবহারকারীর একটি খালি পাসওয়ার্ড থাকতে পারে",
|
||||
"ToastNewUserTagError": "অন্তত একটি ট্যাগ নির্বাচন করতে হবে",
|
||||
"ToastNewUserUsernameError": "একটি ব্যবহারকারীর নাম লিখুন",
|
||||
"ToastNoNewEpisodesFound": "কোন নতুন পর্ব পাওয়া যায়নি",
|
||||
"ToastNoUpdatesNecessary": "কোন আপডেটের প্রয়োজন নেই",
|
||||
"ToastNotificationCreateFailed": "বিজ্ঞপ্তি তৈরি করতে ব্যর্থ",
|
||||
"ToastNotificationDeleteFailed": "বিজ্ঞপ্তি মুছে ফেলতে ব্যর্থ",
|
||||
@@ -946,6 +1033,7 @@
|
||||
"ToastPodcastGetFeedFailed": "পডকাস্ট ফিড পেতে ব্যর্থ হয়েছে",
|
||||
"ToastPodcastNoEpisodesInFeed": "আরএসএস ফিডে কোনো পর্ব পাওয়া যায়নি",
|
||||
"ToastPodcastNoRssFeed": "পডকাস্টের কোন আরএসএস ফিড নেই",
|
||||
"ToastProgressIsNotBeingSynced": "অগ্রগতি সিঙ্ক হচ্ছে না, প্লেব্যাক পুনরায় চালু করুন",
|
||||
"ToastProviderCreatedFailed": "প্রদানকারী যোগ করতে ব্যর্থ হয়েছে",
|
||||
"ToastProviderCreatedSuccess": "নতুন প্রদানকারী যোগ করা হয়েছে",
|
||||
"ToastProviderNameAndUrlRequired": "নাম এবং ইউআরএল আবশ্যক",
|
||||
@@ -972,6 +1060,7 @@
|
||||
"ToastSessionCloseFailed": "অধিবেশন বন্ধ করতে ব্যর্থ হয়েছে",
|
||||
"ToastSessionDeleteFailed": "সেশন মুছে ফেলতে ব্যর্থ",
|
||||
"ToastSessionDeleteSuccess": "সেশন মুছে ফেলা হয়েছে",
|
||||
"ToastSleepTimerDone": "স্লিপ টাইমার হয়ে গেছে... zZzzZz",
|
||||
"ToastSlugMustChange": "স্লাগে অবৈধ অক্ষর রয়েছে",
|
||||
"ToastSlugRequired": "স্লাগ আবশ্যক",
|
||||
"ToastSocketConnected": "সকেট সংযুক্ত",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+78
-4
@@ -19,6 +19,7 @@
|
||||
"ButtonChooseFiles": "Vybrat soubory",
|
||||
"ButtonClearFilter": "Vymazat filtr",
|
||||
"ButtonCloseFeed": "Zavřít kanál",
|
||||
"ButtonCloseSession": "Zavřít otevřenou relaci",
|
||||
"ButtonCollections": "Kolekce",
|
||||
"ButtonConfigureScanner": "Konfigurovat Prohledávání",
|
||||
"ButtonCreate": "Vytvořit",
|
||||
@@ -29,6 +30,8 @@
|
||||
"ButtonEditChapters": "Upravit kapitoly",
|
||||
"ButtonEditPodcast": "Upravit podcast",
|
||||
"ButtonEnable": "Povolit",
|
||||
"ButtonFireAndFail": "Spustit a selhat",
|
||||
"ButtonFireOnTest": "Spustit událost onTest",
|
||||
"ButtonForceReScan": "Vynutit opětovné prohledání",
|
||||
"ButtonFullPath": "Úplná cesta",
|
||||
"ButtonHide": "Skrýt",
|
||||
@@ -58,11 +61,13 @@
|
||||
"ButtonPlaylists": "Seznamy skladeb",
|
||||
"ButtonPrevious": "Předchozí",
|
||||
"ButtonPreviousChapter": "Předchozí Kapitola",
|
||||
"ButtonProbeAudioFile": "Prozkoumat audio soubor",
|
||||
"ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť",
|
||||
"ButtonPurgeItemsCache": "Vyčistit mezipaměť položek",
|
||||
"ButtonQueueAddItem": "Přidat do fronty",
|
||||
"ButtonQueueRemoveItem": "Odstranit z fronty",
|
||||
"ButtonQuickEmbedMetadata": "Rychle Zapsat Metadata",
|
||||
"ButtonQuickEmbed": "Rychle Zapsat",
|
||||
"ButtonQuickEmbedMetadata": "Rychle zapsat Metadata",
|
||||
"ButtonQuickMatch": "Rychlé přiřazení",
|
||||
"ButtonReScan": "Znovu prohledat",
|
||||
"ButtonRead": "Číst",
|
||||
@@ -83,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Uložit seznam skladeb",
|
||||
"ButtonScan": "Prohledat",
|
||||
"ButtonScanLibrary": "Prohledat Knihovnu",
|
||||
"ButtonScrollLeft": "Posunout vlevo",
|
||||
"ButtonScrollRight": "Posunout vpravo",
|
||||
"ButtonSearch": "Hledat",
|
||||
"ButtonSelectFolderPath": "Vybrat cestu ke složce",
|
||||
"ButtonSeries": "Série",
|
||||
@@ -158,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "Aktualizovat notifikaci",
|
||||
"HeaderNotifications": "Oznámení",
|
||||
"HeaderOpenIDConnectAuthentication": "Ověřování pomocí OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "Otevřené relace přehrávače",
|
||||
"HeaderOpenRSSFeed": "Otevřít RSS kanál",
|
||||
"HeaderOtherFiles": "Ostatní soubory",
|
||||
"HeaderPasswordAuthentication": "Autentizace heslem",
|
||||
@@ -175,6 +183,7 @@
|
||||
"HeaderRemoveEpisodes": "Odstranit {0} epizody",
|
||||
"HeaderSavedMediaProgress": "Průběh uložených médií",
|
||||
"HeaderSchedule": "Plán",
|
||||
"HeaderScheduleEpisodeDownloads": "Naplánovat automatické stahování epizod",
|
||||
"HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven",
|
||||
"HeaderSession": "Relace",
|
||||
"HeaderSetBackupSchedule": "Nastavit plán zálohování",
|
||||
@@ -183,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "Experimentální funkce",
|
||||
"HeaderSettingsGeneral": "Obecné",
|
||||
"HeaderSettingsScanner": "Skener",
|
||||
"HeaderSettingsWebClient": "Webový klient",
|
||||
"HeaderSleepTimer": "Časovač vypnutí",
|
||||
"HeaderStatsLargestItems": "Největší položky",
|
||||
"HeaderStatsLongestItems": "Nejdelší položky (hod.)",
|
||||
@@ -220,7 +230,11 @@
|
||||
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
|
||||
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
|
||||
"LabelAlreadyInYourLibrary": "Již ve vaší knihovně",
|
||||
"LabelApiToken": "API Token",
|
||||
"LabelAppend": "Připojit",
|
||||
"LabelAudioBitrate": "Bitový tok zvuku (např. 128k)",
|
||||
"LabelAudioChannels": "Zvukové kanály (1 nebo 2)",
|
||||
"LabelAudioCodec": "Audio Kodek",
|
||||
"LabelAuthor": "Autor",
|
||||
"LabelAuthorFirstLast": "Autor (jméno a příjmení)",
|
||||
"LabelAuthorLastFirst": "Autor (příjmení a jméno)",
|
||||
@@ -233,6 +247,7 @@
|
||||
"LabelAutoRegister": "Automatická registrace",
|
||||
"LabelAutoRegisterDescription": "Automaticky vytvářet nové uživatele po přihlášení",
|
||||
"LabelBackToUser": "Zpět k uživateli",
|
||||
"LabelBackupAudioFiles": "Zálohovat zvukové soubory",
|
||||
"LabelBackupLocation": "Umístění zálohy",
|
||||
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
|
||||
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
|
||||
@@ -241,15 +256,18 @@
|
||||
"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ě.",
|
||||
"LabelBitrate": "Datový tok",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "Knihy",
|
||||
"LabelButtonText": "Text tlačítka",
|
||||
"LabelByAuthor": "od {0}",
|
||||
"LabelChangePassword": "Změnit heslo",
|
||||
"LabelChannels": "Kanály",
|
||||
"LabelChapterCount": "{0} Kapitol",
|
||||
"LabelChapterTitle": "Název kapitoly",
|
||||
"LabelChapters": "Kapitoly",
|
||||
"LabelChaptersFound": "Kapitoly nalezeny",
|
||||
"LabelClickForMoreInfo": "Klikněte pro více informací",
|
||||
"LabelClickToUseCurrentValue": "Klikni pro použití aktuální hodnoty",
|
||||
"LabelClosePlayer": "Zavřít přehrávač",
|
||||
"LabelCodec": "Kodek",
|
||||
"LabelCollapseSeries": "Sbalit sérii",
|
||||
@@ -299,12 +317,25 @@
|
||||
"LabelEmailSettingsTestAddress": "Testovací adresa",
|
||||
"LabelEmbeddedCover": "Vložená obálka",
|
||||
"LabelEnable": "Povolit",
|
||||
"LabelEncodingBackupLocation": "Záloha původních audio souborů bude uložena v:",
|
||||
"LabelEncodingChaptersNotEmbedded": "Kapitoly nejsou vloženy ve vícestopých audioknihách.",
|
||||
"LabelEncodingClearItemCache": "Nezapomeňte pravidelně promazávat mezipaměť položek.",
|
||||
"LabelEncodingFinishedM4B": "Výsledné M4B bude uloženo do složky s audioknihou v:",
|
||||
"LabelEncodingInfoEmbedded": "Metadata budou vložena do audio stop ve složce s audioknihou.",
|
||||
"LabelEncodingStartedNavigation": "Po spuštění úlohy můžete opustit tuto stránku.",
|
||||
"LabelEncodingTimeWarning": "Encoding může zabrat až 30 minut.",
|
||||
"LabelEncodingWarningAdvancedSettings": "Varování: Neměňte toto nastavení pokud neznáte možnosti encodingu ffmpeg.",
|
||||
"LabelEncodingWatcherDisabled": "Pokud máte zakázaný watcher, budete po skončení muset znovu naskenovat tuto audioknihu.",
|
||||
"LabelEnd": "Konec",
|
||||
"LabelEndOfChapter": "Konec kapitoly",
|
||||
"LabelEpisode": "Epizoda",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "Epizoda není propojená s RSS feed",
|
||||
"LabelEpisodeNumber": "Epizoda #{0}",
|
||||
"LabelEpisodeTitle": "Název epizody",
|
||||
"LabelEpisodeType": "Typ epizody",
|
||||
"LabelEpisodeUrlFromRssFeed": "URL epizody z RSS feed",
|
||||
"LabelEpisodes": "Epizody",
|
||||
"LabelEpisodic": "Epizodické",
|
||||
"LabelExample": "Příklad",
|
||||
"LabelExpandSeries": "Rozbalit série",
|
||||
"LabelExpandSubSeries": "Rozbalit podsérie",
|
||||
@@ -332,6 +363,7 @@
|
||||
"LabelFontScale": "Měřítko písma",
|
||||
"LabelFontStrikethrough": "Přeškrtnutí",
|
||||
"LabelFormat": "Formát",
|
||||
"LabelFull": "Plné",
|
||||
"LabelGenre": "Žánr",
|
||||
"LabelGenres": "Žánry",
|
||||
"LabelHardDeleteFile": "Trvale smazat soubor",
|
||||
@@ -374,6 +406,7 @@
|
||||
"LabelLess": "Méně",
|
||||
"LabelLibrariesAccessibleToUser": "Knihovny přístupné uživateli",
|
||||
"LabelLibrary": "Knihovna",
|
||||
"LabelLibraryFilterSublistEmpty": "Žádné {0}",
|
||||
"LabelLibraryItem": "Položka knihovny",
|
||||
"LabelLibraryName": "Název knihovny",
|
||||
"LabelLimit": "Omezit",
|
||||
@@ -386,6 +419,10 @@
|
||||
"LabelLowestPriority": "Nejnižší priorita",
|
||||
"LabelMatchExistingUsersBy": "Přiřadit stávající uživatele podle",
|
||||
"LabelMatchExistingUsersByDescription": "Slouží k propojení stávajících uživatelů. Po propojení budou uživatelé přiřazeni k jedinečnému ID od poskytovatele SSO.",
|
||||
"LabelMaxEpisodesToDownload": "Maximální # epizod pro stažení. Použijte 0 pro bez omezení.",
|
||||
"LabelMaxEpisodesToDownloadPerCheck": "Maximální počet nových epizod ke stažení při jedné kontrole",
|
||||
"LabelMaxEpisodesToKeep": "Maximální počet epizod k zachování",
|
||||
"LabelMaxEpisodesToKeepHelp": "Hodnotou 0 není nastaven žádný maximální limit. Po automatickém stažení nové epizody se odstraní nejstarší epizoda, pokud máte více než X epizod. Při každém novém stažení se odstraní pouze 1 epizoda.",
|
||||
"LabelMediaPlayer": "Přehrávač médií",
|
||||
"LabelMediaType": "Typ média",
|
||||
"LabelMetaTag": "Metaznačka",
|
||||
@@ -431,12 +468,14 @@
|
||||
"LabelOpenIDGroupClaimDescription": "Název požadavku OpenID, který obsahuje seznam uživatelských skupin. Běžně se označuje jako <code>groups</code>. <b>Je-li nakonfigurováno</b>, plikace automaticky přiřadí role na základě členství uživatele ve skupinách, pokud jsou tyto skupiny v požadavku pojmenovány case-insensitive 'admin', 'user' nebo 'guest'. Požadavek by měl obsahovat seznam, a pokud uživatel patří do více skupin, aplikace přiřadí roli odpovídající nejvyšší úrovni práva přístupu. Pokud žádná skupina není shodná, bude přístup odepřen.",
|
||||
"LabelOpenRSSFeed": "Otevřít RSS kanál",
|
||||
"LabelOverwrite": "Přepsat",
|
||||
"LabelPaginationPageXOfY": "Strana {0} z {1}",
|
||||
"LabelPassword": "Heslo",
|
||||
"LabelPath": "Cesta",
|
||||
"LabelPermanent": "Trvalé",
|
||||
"LabelPermissionsAccessAllLibraries": "Má přístup ke všem knihovnám",
|
||||
"LabelPermissionsAccessAllTags": "Má přístup ke všem značkám",
|
||||
"LabelPermissionsAccessExplicitContent": "Má přístup k explicitnímu obsahu",
|
||||
"LabelPermissionsCreateEreader": "Může vytvořit Ereader",
|
||||
"LabelPermissionsDelete": "Může mazat",
|
||||
"LabelPermissionsDownload": "Může stahovat",
|
||||
"LabelPermissionsUpdate": "Může aktualizovat",
|
||||
@@ -460,6 +499,8 @@
|
||||
"LabelPubDate": "Datum vydání",
|
||||
"LabelPublishYear": "Rok vydání",
|
||||
"LabelPublishedDate": "Vydáno {0}",
|
||||
"LabelPublishedDecade": "Publikováno (dekáda)",
|
||||
"LabelPublishedDecades": "Publikováno (dekády)",
|
||||
"LabelPublisher": "Vydavatel",
|
||||
"LabelPublishers": "Vydavatelé",
|
||||
"LabelRSSFeedCustomOwnerEmail": "Vlastní e-mail vlastníka",
|
||||
@@ -479,24 +520,32 @@
|
||||
"LabelRedo": "Přepracovat",
|
||||
"LabelRegion": "Region",
|
||||
"LabelReleaseDate": "Datum vydání",
|
||||
"LabelRemoveAllMetadataAbs": "Odebrat všechny soubory metadata.abs",
|
||||
"LabelRemoveAllMetadataJson": "Smazat všechny soubory metadata.json",
|
||||
"LabelRemoveCover": "Odstranit obálku",
|
||||
"LabelRemoveMetadataFile": "Odstranit soubory metadat ve složkách položek knihovny",
|
||||
"LabelRemoveMetadataFileHelp": "Odstraníte všechny soubory metadata.json a metadata.abs ve svých složkách {0}.",
|
||||
"LabelRowsPerPage": "Řádky na stránku",
|
||||
"LabelSearchTerm": "Vyhledat termín",
|
||||
"LabelSearchTitle": "Vyhledat název",
|
||||
"LabelSearchTitleOrASIN": "Vyhledat název nebo ASIN",
|
||||
"LabelSeason": "Sezóna",
|
||||
"LabelSeasonNumber": "Sezóna č.{0}",
|
||||
"LabelSelectAll": "Vybrat vše",
|
||||
"LabelSelectAllEpisodes": "Vybrat všechny epizody",
|
||||
"LabelSelectEpisodesShowing": "Vyberte {0} epizody, které se zobrazují",
|
||||
"LabelSelectUsers": "Vybrat uživatele",
|
||||
"LabelSendEbookToDevice": "Odeslat e-knihu do...",
|
||||
"LabelSequence": "Sekvence",
|
||||
"LabelSerial": "Sériové",
|
||||
"LabelSeries": "Série",
|
||||
"LabelSeriesName": "Název série",
|
||||
"LabelSeriesProgress": "Průběh série",
|
||||
"LabelServerLogLevel": "Úroveň protokolu serveru",
|
||||
"LabelServerYearReview": "Přehled roku na serveru ({0})",
|
||||
"LabelSetEbookAsPrimary": "Nastavit jako primární",
|
||||
"LabelSetEbookAsSupplementary": "Nastavit jako doplňkové",
|
||||
"LabelSettingsAllowIframe": "Povolit vložení do rámce iframe",
|
||||
"LabelSettingsAudiobooksOnly": "Pouze audioknihy",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "Povolením tohoto nastavení budou soubory e-knih ignorovány, pokud nejsou ve složce audioknih, v takovém případě budou nastaveny jako doplňkové e-knihy",
|
||||
"LabelSettingsBookshelfViewHelp": "Skeumorfní design s dřevěnými policemi",
|
||||
@@ -518,6 +567,9 @@
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "Série, které mají jedinou knihu, budou skryty na stránce série a na domovské stránce.",
|
||||
"LabelSettingsHomePageBookshelfView": "Domovská stránka používá zobrazení police s knihami",
|
||||
"LabelSettingsLibraryBookshelfView": "Knihovna používá zobrazení police s knihami",
|
||||
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Procento dokončení je vyšší než",
|
||||
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Zbývající čas je kratší než (sekund)",
|
||||
"LabelSettingsLibraryMarkAsFinishedWhen": "Označit položku médií jako dokončenou, když",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Přeskočit předchozí knihy v pokračování série",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Polička Pokračovat v sérii na domovské stránce zobrazuje první nezačatou knihu v sériích, které mají alespoň jednu knihu dokončenou a žádnou rozečtenou. Povolením tohoto nastavení budou série pokračovat od poslední dokončené knihy namísto první nezačaté knihy.",
|
||||
"LabelSettingsParseSubtitles": "Analzyovat podtitul",
|
||||
@@ -536,12 +588,16 @@
|
||||
"LabelSettingsStoreMetadataWithItemHelp": "Ve výchozím nastavení jsou soubory metadat uloženy v adresáři /metadata/items, povolením tohoto nastavení budou soubory metadat uloženy ve složkách položek knihovny",
|
||||
"LabelSettingsTimeFormat": "Formát času",
|
||||
"LabelShare": "Sdílet",
|
||||
"LabelShareOpen": "Otevřít sdílení",
|
||||
"LabelShareURL": "Sdílet URL",
|
||||
"LabelShowAll": "Zobrazit vše",
|
||||
"LabelShowSeconds": "Zobrazit sekundy",
|
||||
"LabelShowSubtitles": "Zobrazit titulky",
|
||||
"LabelSize": "Velikost",
|
||||
"LabelSleepTimer": "Časovač vypnutí",
|
||||
"LabelSlug": "URL název",
|
||||
"LabelSortAscending": "Vzestupně",
|
||||
"LabelSortDescending": "Sestupně",
|
||||
"LabelStart": "Spustit",
|
||||
"LabelStartTime": "Čas Spuštění",
|
||||
"LabelStarted": "Spuštěno",
|
||||
@@ -580,6 +636,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} minut",
|
||||
"LabelTimeDurationXSeconds": "{0} sekund",
|
||||
"LabelTimeInMinutes": "Čas v minutách",
|
||||
"LabelTimeLeft": "{0} zbývá",
|
||||
"LabelTimeListened": "Čas poslechu",
|
||||
"LabelTimeListenedToday": "Čas poslechu dnes",
|
||||
"LabelTimeRemaining": "{0} zbývá",
|
||||
@@ -587,6 +644,7 @@
|
||||
"LabelTitle": "Název",
|
||||
"LabelToolsEmbedMetadata": "Vložit metadata",
|
||||
"LabelToolsEmbedMetadataDescription": "Vložit metadata do zvukových souborů včetně obálky a kapitol.",
|
||||
"LabelToolsM4bEncoder": "Enkodér M4B",
|
||||
"LabelToolsMakeM4b": "Vytvořit soubor audioknihy M4B",
|
||||
"LabelToolsMakeM4bDescription": "Vygenerovat soubor audioknihy M4B s vloženými metadaty, obálkou a kapitolami.",
|
||||
"LabelToolsSplitM4b": "Rozdělit M4B na MP3",
|
||||
@@ -599,6 +657,7 @@
|
||||
"LabelTracksMultiTrack": "Více stop",
|
||||
"LabelTracksNone": "Žádné stopy",
|
||||
"LabelTracksSingleTrack": "Jedna stopa",
|
||||
"LabelTrailer": "Upoutávka",
|
||||
"LabelType": "Typ",
|
||||
"LabelUnabridged": "Nezkráceno",
|
||||
"LabelUndo": "Zpět",
|
||||
@@ -610,10 +669,13 @@
|
||||
"LabelUpdateDetailsHelp": "Povolit přepsání existujících údajů o vybraných knihách, když je nalezena shoda",
|
||||
"LabelUpdatedAt": "Aktualizováno v",
|
||||
"LabelUploaderDragAndDrop": "Přetáhnout soubory nebo složky",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Přetáhnout a upustit soubory",
|
||||
"LabelUploaderDropFiles": "Odstranit soubory",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Automaticky načíst název, autora a sérii",
|
||||
"LabelUseAdvancedOptions": "Použít pokročilé možnosti",
|
||||
"LabelUseChapterTrack": "Použít stopu kapitoly",
|
||||
"LabelUseFullTrack": "Použít celou stopu",
|
||||
"LabelUseZeroForUnlimited": "Použijte 0 pro neomezené",
|
||||
"LabelUser": "Uživatel",
|
||||
"LabelUsername": "Uživatelské jméno",
|
||||
"LabelValue": "Hodnota",
|
||||
@@ -623,6 +685,8 @@
|
||||
"LabelViewPlayerSettings": "Zobrazit nastavení přehrávače",
|
||||
"LabelViewQueue": "Zobrazit frontu přehrávače",
|
||||
"LabelVolume": "Hlasitost",
|
||||
"LabelWebRedirectURLsDescription": "Autorizujte tyto adresy URL ve zprostředkovateli OAuth, abyste po přihlášení umožnili přesměrování zpět do webové aplikace:",
|
||||
"LabelWebRedirectURLsSubfolder": "Podsložka pro přesměrování adres URL",
|
||||
"LabelWeekdaysToRun": "Dny v týdnu ke spuštění",
|
||||
"LabelXBooks": "{0} knih",
|
||||
"LabelXItems": "{0} položky",
|
||||
@@ -660,6 +724,7 @@
|
||||
"MessageConfirmDeleteMetadataProvider": "Opravdu chcete vymazat vlastního poskytovatele metadat \"{0}\"?",
|
||||
"MessageConfirmDeleteNotification": "Opravdu chcete vymazat tuto notifikaci?",
|
||||
"MessageConfirmDeleteSession": "Opravdu chcete smazat tuto relaci?",
|
||||
"MessageConfirmEmbedMetadataInAudioFiles": "Jste si jisti, že chcete vložit metadata do {0} zvukových souborů?",
|
||||
"MessageConfirmForceReScan": "Opravdu chcete vynutit opětovné prohledání?",
|
||||
"MessageConfirmMarkAllEpisodesFinished": "Opravdu chcete označit všechny epizody jako dokončené?",
|
||||
"MessageConfirmMarkAllEpisodesNotFinished": "Opravdu chcete označit všechny epizody jako nedokončené?",
|
||||
@@ -667,9 +732,11 @@
|
||||
"MessageConfirmMarkItemNotFinished": "Opravdu chcete označit \"{0}\" jako nedokončené?",
|
||||
"MessageConfirmMarkSeriesFinished": "Opravdu chcete označit všechny knihy z této série jako dokončené?",
|
||||
"MessageConfirmMarkSeriesNotFinished": "Opravdu chcete označit všechny knihy z této série jako nedokončené?",
|
||||
"MessageConfirmNotificationTestTrigger": "Spustit toto oznámení s testovacími daty?",
|
||||
"MessageConfirmPurgeCache": "Vyčistit mezipaměť odstraní celý adresář na adrese <code>/metadata/cache</code>. <br /><br />Určitě chcete odstranit adresář mezipaměti?",
|
||||
"MessageConfirmPurgeItemsCache": "Vyčištění mezipaměti položek odstraní celý adresář <code>/metadata/cache/items</code>.<br />Jste si jistí?",
|
||||
"MessageConfirmQuickEmbed": "Varování! Rychlé vložení nezálohuje vaše zvukové soubory. Ujistěte se, že máte zálohu zvukových souborů. <br><br>Chcete pokračovat?",
|
||||
"MessageConfirmQuickMatchEpisodes": "Pokud je nalezena shoda při rychlém párování epizod, dojde k přepsání podrobností. Aktualizovány budou pouze nespárované epizody. Jste si jisti?",
|
||||
"MessageConfirmReScanLibraryItems": "Opravdu chcete znovu prohledat {0} položky?",
|
||||
"MessageConfirmRemoveAllChapters": "Opravdu chcete odstranit všechny kapitoly?",
|
||||
"MessageConfirmRemoveAuthor": "Opravdu chcete odstranit autora \"{0}\"?",
|
||||
@@ -677,6 +744,7 @@
|
||||
"MessageConfirmRemoveEpisode": "Opravdu chcete odstranit epizodu \"{0}\"?",
|
||||
"MessageConfirmRemoveEpisodes": "Opravdu chcete odstranit {0} epizody?",
|
||||
"MessageConfirmRemoveListeningSessions": "Opravdu chcete odebrat {0} poslechových relací?",
|
||||
"MessageConfirmRemoveMetadataFiles": "Jste si jisti, že chcete odstranit všechny metadata.{0} soubory ve složkách s položkami ve vaší knihovně?",
|
||||
"MessageConfirmRemoveNarrator": "Opravdu chcete odebrat předčítání \"{0}\"?",
|
||||
"MessageConfirmRemovePlaylist": "Opravdu chcete odstranit svůj playlist \"{0}\"?",
|
||||
"MessageConfirmRenameGenre": "Opravdu chcete přejmenovat žánr \"{0}\" na \"{1}\" pro všechny položky?",
|
||||
@@ -692,6 +760,7 @@
|
||||
"MessageDragFilesIntoTrackOrder": "Přetáhněte soubory do správného pořadí stop",
|
||||
"MessageEmbedFailed": "Vložení selhalo!",
|
||||
"MessageEmbedFinished": "Vložení dokončeno!",
|
||||
"MessageEmbedQueue": "Zařazeno do fronty pro vložení metadat ({0} ve frontě)",
|
||||
"MessageEpisodesQueuedForDownload": "{0} Epizody zařazené do fronty ke stažení",
|
||||
"MessageEreaderDevices": "Aby bylo zajištěno doručení elektronických knih, může být nutné přidat výše uvedenou e-mailovou adresu jako platného odesílatele pro každé zařízení uvedené níže.",
|
||||
"MessageFeedURLWillBe": "URL zdroje bude {0}",
|
||||
@@ -702,7 +771,6 @@
|
||||
"MessageItemsSelected": "{0} vybraných položek",
|
||||
"MessageItemsUpdated": "{0} položky byly aktualizovány",
|
||||
"MessageJoinUsOn": "Přidejte se k nám",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} poslechových relací za poslední rok",
|
||||
"MessageLoading": "Načítá se...",
|
||||
"MessageLoadingFolders": "Načítám složky...",
|
||||
"MessageLogsDescription": "Protokoly se ukládají do souborů JSON v <code>/metadata/logs</code>. Protokoly o pádech jsou uloženy v <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -736,6 +804,7 @@
|
||||
"MessageNoLogs": "Žádné protokoly",
|
||||
"MessageNoMediaProgress": "Žádný průběh médií",
|
||||
"MessageNoNotifications": "Žádná oznámení",
|
||||
"MessageNoPodcastFeed": "Neplatný podcast: Žádný kanál",
|
||||
"MessageNoPodcastsFound": "Nebyly nalezeny žádné podcasty",
|
||||
"MessageNoResults": "Žádné výsledky",
|
||||
"MessageNoSearchResultsFor": "Nebyly nalezeny žádné výsledky hledání pro \"{0}\"",
|
||||
@@ -752,7 +821,10 @@
|
||||
"MessagePlaylistCreateFromCollection": "Vytvořit seznam skladeb z kolekce",
|
||||
"MessagePleaseWait": "Čekejte prosím...",
|
||||
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nemá žádnou adresu URL kanálu RSS, kterou by mohl použít pro porovnávání",
|
||||
"MessageQuickMatchDescription": "Vyplňte prázdné detaily položky a obálku prvním výsledkem shody z '{0}'. Nepřepisuje podrobnosti, pokud není povoleno nastavení serveru \"Preferovat párování metadata\".",
|
||||
"MessageQuickEmbedInProgress": "Probíhá rychlé vkládání",
|
||||
"MessageQuickEmbedQueue": "Zařazeno do fronty pro rychlé vložení ({0} ve frontě)",
|
||||
"MessageQuickMatchAllEpisodes": "Rychlá shoda všech epizod",
|
||||
"MessageQuickMatchDescription": "Vyplnit prázdné detaily položky a obálky prvním výsledkem shody z '{0}'. Nepřepisuje detaily, pokud není povoleno nastavení serveru 'Preferovat shodná metadata'.",
|
||||
"MessageRemoveChapter": "Odstranit kapitolu",
|
||||
"MessageRemoveEpisodes": "Odstranit {0} epizodu",
|
||||
"MessageRemoveFromPlayerQueue": "Odstranit z fronty přehrávače",
|
||||
@@ -783,10 +855,13 @@
|
||||
"MessageTaskFailedToMergeAudioFiles": "Spojení audio souborů selhalo",
|
||||
"MessageTaskFailedToMoveM4bFile": "Přesunutí m4b souboru selhalo",
|
||||
"MessageTaskFailedToWriteMetadataFile": "Zápis souboru metadat selhal",
|
||||
"MessageTaskMatchingBooksInLibrary": "Párování knih v knihovně „{0}“",
|
||||
"MessageTaskNoFilesToScan": "Žádné soubory ke skenování",
|
||||
"MessageTaskOpmlImport": "Import OPML",
|
||||
"MessageTaskOpmlImportDescription": "Vytváření podcastů z {0} RSS feedů",
|
||||
"MessageTaskOpmlImportFeed": "Importní zdroj OPML",
|
||||
"MessageTaskOpmlImportFeedDescription": "Importování RSS feedu \"{0}\"",
|
||||
"MessageTaskOpmlImportFeedFailed": "Nepodařilo se získat kanál podcastu",
|
||||
"MessageTaskOpmlImportFeedPodcastDescription": "Vytváření podcastu \"{0}\"",
|
||||
"MessageTaskOpmlImportFeedPodcastExists": "Podcast se stejnou cestou již existuje",
|
||||
"MessageTaskOpmlImportFeedPodcastFailed": "Vytváření podcastu selhalo",
|
||||
@@ -867,7 +942,6 @@
|
||||
"ToastChaptersHaveErrors": "Kapitoly obsahují chyby",
|
||||
"ToastChaptersMustHaveTitles": "Kapitoly musí mít názvy",
|
||||
"ToastChaptersRemoved": "Kapitoly odstraněny",
|
||||
"ToastCollectionItemsRemoveSuccess": "Položky odstraněny z kolekce",
|
||||
"ToastCollectionRemoveSuccess": "Kolekce odstraněna",
|
||||
"ToastCollectionUpdateSuccess": "Kolekce aktualizována",
|
||||
"ToastCoverUpdateFailed": "Aktualizace obálky selhala",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"ButtonChooseFiles": "Vælg filer",
|
||||
"ButtonClearFilter": "Ryd filter",
|
||||
"ButtonCloseFeed": "Luk feed",
|
||||
"ButtonCloseSession": "Luk Åben Session",
|
||||
"ButtonCollections": "Samlinger",
|
||||
"ButtonConfigureScanner": "Konfigurer scanner",
|
||||
"ButtonCreate": "Opret",
|
||||
@@ -29,7 +30,9 @@
|
||||
"ButtonEditChapters": "Rediger kapitler",
|
||||
"ButtonEditPodcast": "Rediger podcast",
|
||||
"ButtonEnable": "Aktiver",
|
||||
"ButtonForceReScan": "Tvungen genindlæsning",
|
||||
"ButtonFireAndFail": "Affyring Og Fejl",
|
||||
"ButtonFireOnTest": "Affyring vedTest begivenhed",
|
||||
"ButtonForceReScan": "Tving genindlæsning",
|
||||
"ButtonFullPath": "Fuld sti",
|
||||
"ButtonHide": "Skjul",
|
||||
"ButtonHome": "Hjem",
|
||||
@@ -536,7 +539,6 @@
|
||||
"MessageItemsSelected": "{0} elementer valgt",
|
||||
"MessageItemsUpdated": "{0} elementer opdateret",
|
||||
"MessageJoinUsOn": "Deltag i os på",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} lyttesessioner i det sidste år",
|
||||
"MessageLoading": "Indlæser...",
|
||||
"MessageLoadingFolders": "Indlæser mapper...",
|
||||
"MessageM4BFailed": "M4B mislykkedes!",
|
||||
@@ -637,7 +639,6 @@
|
||||
"ToastBookmarkUpdateSuccess": "Bogmærke opdateret",
|
||||
"ToastChaptersHaveErrors": "Kapitler har fejl",
|
||||
"ToastChaptersMustHaveTitles": "Kapitler skal have titler",
|
||||
"ToastCollectionItemsRemoveSuccess": "Element(er) fjernet fra samlingen",
|
||||
"ToastCollectionRemoveSuccess": "Samling fjernet",
|
||||
"ToastCollectionUpdateSuccess": "Samling opdateret",
|
||||
"ToastItemCoverUpdateSuccess": "Varens omslag opdateret",
|
||||
|
||||
+77
-11
@@ -71,8 +71,8 @@
|
||||
"ButtonQuickMatch": "Schnellabgleich",
|
||||
"ButtonReScan": "Neu scannen",
|
||||
"ButtonRead": "Lesen",
|
||||
"ButtonReadLess": "Weniger anzeigen",
|
||||
"ButtonReadMore": "Mehr anzeigen",
|
||||
"ButtonReadLess": "weniger Anzeigen",
|
||||
"ButtonReadMore": "Mehr Anzeigen",
|
||||
"ButtonRefresh": "Neu Laden",
|
||||
"ButtonRemove": "Entfernen",
|
||||
"ButtonRemoveAll": "Alles entfernen",
|
||||
@@ -88,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Speichere die Titelliste",
|
||||
"ButtonScan": "Partial-Scan (nur geänderte/neue Medien)",
|
||||
"ButtonScanLibrary": "Bibliothek scannen",
|
||||
"ButtonScrollLeft": "Nach Links scrollen",
|
||||
"ButtonScrollRight": "Nach Rechts scrollen",
|
||||
"ButtonSearch": "Suchen",
|
||||
"ButtonSelectFolderPath": "Ordnerpfad auswählen",
|
||||
"ButtonSeries": "Serien",
|
||||
@@ -163,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "Benachrichtigung bearbeiten",
|
||||
"HeaderNotifications": "Benachrichtigungen",
|
||||
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
|
||||
"HeaderOpenListeningSessions": "Aktive Hörbuch-Sitzungen",
|
||||
"HeaderOpenRSSFeed": "RSS-Feed öffnen",
|
||||
"HeaderOtherFiles": "Sonstige Dateien",
|
||||
"HeaderPasswordAuthentication": "Passwortauthentifizierung",
|
||||
@@ -180,6 +183,7 @@
|
||||
"HeaderRemoveEpisodes": "Entferne {0} Episoden",
|
||||
"HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte",
|
||||
"HeaderSchedule": "Zeitplan",
|
||||
"HeaderScheduleEpisodeDownloads": "Automatische Episoden-Downloads planen",
|
||||
"HeaderScheduleLibraryScans": "Automatische Bibliotheksscans",
|
||||
"HeaderSession": "Sitzung",
|
||||
"HeaderSetBackupSchedule": "Zeitplan für die Datensicherung festlegen",
|
||||
@@ -188,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "Experimentelle Funktionen",
|
||||
"HeaderSettingsGeneral": "Allgemein",
|
||||
"HeaderSettingsScanner": "Scanner",
|
||||
"HeaderSettingsWebClient": "Web-Client",
|
||||
"HeaderSleepTimer": "Sleep-Timer",
|
||||
"HeaderStatsLargestItems": "Größte Medien",
|
||||
"HeaderStatsLongestItems": "Längste Medien (h)",
|
||||
@@ -218,13 +223,14 @@
|
||||
"LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen",
|
||||
"LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu",
|
||||
"LabelAddedAt": "Hinzugefügt am",
|
||||
"LabelAddedDate": "Hinzugefügt {0}",
|
||||
"LabelAddedDate": "{0} Hinzugefügt",
|
||||
"LabelAdminUsersOnly": "Nur Admin Benutzer",
|
||||
"LabelAll": "Alle",
|
||||
"LabelAllUsers": "Alle Benutzer",
|
||||
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
|
||||
"LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste",
|
||||
"LabelAlreadyInYourLibrary": "Bereits in der Bibliothek",
|
||||
"LabelApiToken": "API Schlüssel",
|
||||
"LabelAppend": "Anhängen",
|
||||
"LabelAudioBitrate": "Audiobitrate (z. B. 128 kbit/s)",
|
||||
"LabelAudioChannels": "Audiokanäle (1 oder 2)",
|
||||
@@ -250,15 +256,18 @@
|
||||
"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.",
|
||||
"LabelBitrate": "Bitrate",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "Bücher",
|
||||
"LabelButtonText": "Knopftext",
|
||||
"LabelByAuthor": "von {0}",
|
||||
"LabelChangePassword": "Passwort ändern",
|
||||
"LabelChannels": "Kanäle",
|
||||
"LabelChapterCount": "{0} Kapitel",
|
||||
"LabelChapterTitle": "Kapitelüberschrift",
|
||||
"LabelChapters": "Kapitel",
|
||||
"LabelChaptersFound": "Gefundene Kapitel",
|
||||
"LabelClickForMoreInfo": "Klicken für mehr Informationen",
|
||||
"LabelClickToUseCurrentValue": "Anklicken um aktuellen Wert zu verwenden",
|
||||
"LabelClosePlayer": "Player schließen",
|
||||
"LabelCodec": "Codec",
|
||||
"LabelCollapseSeries": "Serien einklappen",
|
||||
@@ -316,12 +325,17 @@
|
||||
"LabelEncodingStartedNavigation": "Sobald die Aufgabe gestartet ist, kann die Seite verlassen werden.",
|
||||
"LabelEncodingTimeWarning": "Kodierung kann bis zu 30 Minuten dauern.",
|
||||
"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",
|
||||
"LabelEndOfChapter": "Ende des Kapitels",
|
||||
"LabelEpisode": "Episode",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "Episode nicht mit RSS-Feed verknüpft",
|
||||
"LabelEpisodeNumber": "Episode #{0}",
|
||||
"LabelEpisodeTitle": "Episodentitel",
|
||||
"LabelEpisodeType": "Episodentyp",
|
||||
"LabelEpisodeUrlFromRssFeed": "Episoden URL vom RSS-Feed",
|
||||
"LabelEpisodes": "Episoden",
|
||||
"LabelEpisodic": "Episodisch",
|
||||
"LabelExample": "Beispiel",
|
||||
"LabelExpandSeries": "Serie ausklappen",
|
||||
"LabelExpandSubSeries": "Unterserie ausklappen",
|
||||
@@ -349,6 +363,7 @@
|
||||
"LabelFontScale": "Schriftgröße",
|
||||
"LabelFontStrikethrough": "Durchgestrichen",
|
||||
"LabelFormat": "Format",
|
||||
"LabelFull": "Voll",
|
||||
"LabelGenre": "Kategorie",
|
||||
"LabelGenres": "Kategorien",
|
||||
"LabelHardDeleteFile": "Datei dauerhaft löschen",
|
||||
@@ -404,6 +419,10 @@
|
||||
"LabelLowestPriority": "Niedrigste Priorität",
|
||||
"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",
|
||||
"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",
|
||||
"LabelMediaType": "Medientyp",
|
||||
"LabelMetaTag": "Meta Schlagwort",
|
||||
@@ -449,12 +468,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.",
|
||||
"LabelOpenRSSFeed": "Öffne RSS-Feed",
|
||||
"LabelOverwrite": "Überschreiben",
|
||||
"LabelPaginationPageXOfY": "Seite {0} von {1}",
|
||||
"LabelPassword": "Passwort",
|
||||
"LabelPath": "Pfad",
|
||||
"LabelPermanent": "Dauerhaft",
|
||||
"LabelPermissionsAccessAllLibraries": "Zugriff auf alle Bibliotheken",
|
||||
"LabelPermissionsAccessAllTags": "Zugriff auf alle Schlagwörter",
|
||||
"LabelPermissionsAccessExplicitContent": "Zugriff auf explizite (alterbeschränkte) Inhalte",
|
||||
"LabelPermissionsCreateEreader": "Kann E-Reader erstellen",
|
||||
"LabelPermissionsDelete": "Darf Löschen",
|
||||
"LabelPermissionsDownload": "Herunterladen",
|
||||
"LabelPermissionsUpdate": "Aktualisieren",
|
||||
@@ -499,18 +520,24 @@
|
||||
"LabelRedo": "Wiederholen",
|
||||
"LabelRegion": "Region",
|
||||
"LabelReleaseDate": "Veröffentlichungsdatum",
|
||||
"LabelRemoveAllMetadataAbs": "Alle metadata.abs Dateien löschen",
|
||||
"LabelRemoveAllMetadataJson": "Alle metadata.json Dateien löschen",
|
||||
"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",
|
||||
"LabelSearchTerm": "Begriff suchen",
|
||||
"LabelSearchTitle": "Titel suchen",
|
||||
"LabelSearchTitleOrASIN": "Titel oder ASIN suchen",
|
||||
"LabelSeason": "Staffel",
|
||||
"LabelSeasonNumber": "Staffel #{0}",
|
||||
"LabelSelectAll": "Alles auswählen",
|
||||
"LabelSelectAllEpisodes": "Alle Episoden auswählen",
|
||||
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
|
||||
"LabelSelectUsers": "Benutzer auswählen",
|
||||
"LabelSendEbookToDevice": "E-Buch senden an …",
|
||||
"LabelSequence": "Reihenfolge",
|
||||
"LabelSerial": "fortlaufend",
|
||||
"LabelSeries": "Serien",
|
||||
"LabelSeriesName": "Serienname",
|
||||
"LabelSeriesProgress": "Serienfortschritt",
|
||||
@@ -518,6 +545,7 @@
|
||||
"LabelServerYearReview": "Server Jahr in Übersicht ({0})",
|
||||
"LabelSetEbookAsPrimary": "Als Hauptbuch setzen",
|
||||
"LabelSetEbookAsSupplementary": "Als Ergänzung setzen",
|
||||
"LabelSettingsAllowIframe": "Einbetten in einem iFrame erlauben",
|
||||
"LabelSettingsAudiobooksOnly": "Nur Hörbücher",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "Wenn du diese Einstellung aktivierst, werden E-Buch-Dateien ignoriert, es sei denn, sie befinden sich in einem Hörbuchordner. In diesem Fall werden sie als zusätzliche E-Bücher festgelegt",
|
||||
"LabelSettingsBookshelfViewHelp": "Skeumorphes Design mit Holzeinlegeböden",
|
||||
@@ -539,6 +567,9 @@
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "Serien, die nur ein einzelnes Buch enthalten, werden auf der Startseite und in der Serienansicht ausgeblendet.",
|
||||
"LabelSettingsHomePageBookshelfView": "Startseite 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",
|
||||
"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",
|
||||
@@ -557,7 +588,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",
|
||||
"LabelSettingsTimeFormat": "Zeitformat",
|
||||
"LabelShare": "Freigeben",
|
||||
"LabelShareOpen": "Freigabe",
|
||||
"LabelShareOpen": "Freigeben",
|
||||
"LabelShareURL": "Freigabe URL",
|
||||
"LabelShowAll": "Alles anzeigen",
|
||||
"LabelShowSeconds": "Zeige Sekunden",
|
||||
@@ -565,6 +596,8 @@
|
||||
"LabelSize": "Größe",
|
||||
"LabelSleepTimer": "Schlummerfunktion",
|
||||
"LabelSlug": "URL Teil",
|
||||
"LabelSortAscending": "Aufsteigend",
|
||||
"LabelSortDescending": "Absteigend",
|
||||
"LabelStart": "Start",
|
||||
"LabelStartTime": "Startzeit",
|
||||
"LabelStarted": "Gestartet",
|
||||
@@ -603,6 +636,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} Minuten",
|
||||
"LabelTimeDurationXSeconds": "{0} Sekunden",
|
||||
"LabelTimeInMinutes": "Zeit in Minuten",
|
||||
"LabelTimeLeft": "{0} verbleibend",
|
||||
"LabelTimeListened": "Gehörte Zeit",
|
||||
"LabelTimeListenedToday": "Heute gehörte Zeit",
|
||||
"LabelTimeRemaining": "{0} verbleibend",
|
||||
@@ -623,6 +657,7 @@
|
||||
"LabelTracksMultiTrack": "Mehrfachdatei",
|
||||
"LabelTracksNone": "Keine Dateien",
|
||||
"LabelTracksSingleTrack": "Einzeldatei",
|
||||
"LabelTrailer": "Vorschau",
|
||||
"LabelType": "Typ",
|
||||
"LabelUnabridged": "Ungekürzt",
|
||||
"LabelUndo": "Rückgängig machen",
|
||||
@@ -634,11 +669,13 @@
|
||||
"LabelUpdateDetailsHelp": "Erlaube das Überschreiben bestehender Details für die ausgewählten Hörbücher, wenn eine Übereinstimmung gefunden wird",
|
||||
"LabelUpdatedAt": "Aktualisiert am",
|
||||
"LabelUploaderDragAndDrop": "Ziehen und Ablegen von Dateien oder Ordnern",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Dateien per Drag & Drop hierher ziehen",
|
||||
"LabelUploaderDropFiles": "Dateien löschen",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Automatisches Aktualisieren von Titel, Autor und Serie",
|
||||
"LabelUseAdvancedOptions": "Nutze Erweiterte Optionen",
|
||||
"LabelUseChapterTrack": "Kapiteldatei verwenden",
|
||||
"LabelUseFullTrack": "Gesamte Datei verwenden",
|
||||
"LabelUseZeroForUnlimited": "0 für unbegrenzt",
|
||||
"LabelUser": "Benutzer",
|
||||
"LabelUsername": "Benutzername",
|
||||
"LabelValue": "Wert",
|
||||
@@ -648,11 +685,13 @@
|
||||
"LabelViewPlayerSettings": "Zeige player Einstellungen",
|
||||
"LabelViewQueue": "Player-Warteschlange anzeigen",
|
||||
"LabelVolume": "Lautstärke",
|
||||
"LabelWebRedirectURLsDescription": "Autorisiere diese URLs bei deinem 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",
|
||||
"LabelXBooks": "{0} Bücher",
|
||||
"LabelXItems": "{0} Medien",
|
||||
"LabelYearReviewHide": "Verstecke Jahr in Übersicht",
|
||||
"LabelYearReviewShow": "Zeige Jahr in Übersicht",
|
||||
"LabelYearReviewHide": "Jahresrückblick verbergen",
|
||||
"LabelYearReviewShow": "Jahresrückblick anzeigen",
|
||||
"LabelYourAudiobookDuration": "Laufzeit deines Mediums",
|
||||
"LabelYourBookmarks": "Lesezeichen",
|
||||
"LabelYourPlaylists": "Eigene Wiedergabelisten",
|
||||
@@ -697,6 +736,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?",
|
||||
"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?",
|
||||
"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?",
|
||||
"MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?",
|
||||
"MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?",
|
||||
@@ -704,6 +744,7 @@
|
||||
"MessageConfirmRemoveEpisode": "Episode \"{0}\" wird 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?",
|
||||
"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?",
|
||||
"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?",
|
||||
@@ -719,6 +760,7 @@
|
||||
"MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge",
|
||||
"MessageEmbedFailed": "Einbetten fehlgeschlagen!",
|
||||
"MessageEmbedFinished": "Einbettung abgeschlossen!",
|
||||
"MessageEmbedQueue": "Eingereiht zum einbinden von Metadaten ({0} in Warteschlange)",
|
||||
"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.",
|
||||
"MessageFeedURLWillBe": "Feed-URL wird {0} sein",
|
||||
@@ -729,7 +771,6 @@
|
||||
"MessageItemsSelected": "{0} ausgewählte Medien",
|
||||
"MessageItemsUpdated": "{0} Medien aktualisiert",
|
||||
"MessageJoinUsOn": "Besuche uns auf",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} Ereignisse im letzten Jahr",
|
||||
"MessageLoading": "Wird geladen …",
|
||||
"MessageLoadingFolders": "Lade Ordner...",
|
||||
"MessageLogsDescription": "Die Logs werdern in <code>/metadata/logs</code> als JSON Dateien gespeichert. Crash logs werden in <code>/metadata/logs/crash_logs.txt</code> gespeichert.",
|
||||
@@ -780,6 +821,10 @@
|
||||
"MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung",
|
||||
"MessagePleaseWait": "Bitte warten...",
|
||||
"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.",
|
||||
"MessageRemoveChapter": "Kapitel entfernen",
|
||||
"MessageRemoveEpisodes": "Entferne {0} Episode(n)",
|
||||
@@ -795,7 +840,7 @@
|
||||
"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",
|
||||
"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}?",
|
||||
"MessageTaskAudioFileNotWritable": "Die Audiodatei \"{0}\" ist schreibgeschützt",
|
||||
"MessageTaskCanceledByUser": "Aufgabe vom Benutzer abgebrochen",
|
||||
@@ -822,6 +867,9 @@
|
||||
"MessageTaskOpmlImportFeedPodcastExists": "Der Podcast ist bereits im Pfad vorhanden",
|
||||
"MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen",
|
||||
"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",
|
||||
"MessageTaskScanItemsMissing": "{0} fehlend",
|
||||
"MessageTaskScanItemsUpdated": "{0} aktualisiert",
|
||||
@@ -846,6 +894,10 @@
|
||||
"NoteUploaderFoldersWithMediaFiles": "Ordner mit Mediendateien werden als separate Bibliothekselemente 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.",
|
||||
"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",
|
||||
"PlaceholderNewFolderPath": "Neuer Ordnerpfad",
|
||||
"PlaceholderNewPlaylist": "Neuer Wiedergabelistenname",
|
||||
@@ -871,6 +923,7 @@
|
||||
"StatsYearInReview": "DAS JAHR IM RÜCKBLICK",
|
||||
"ToastAccountUpdateSuccess": "Konto aktualisiert",
|
||||
"ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig",
|
||||
"ToastAsinRequired": "ASIN ist erforderlich",
|
||||
"ToastAuthorImageRemoveSuccess": "Autorenbild entfernt",
|
||||
"ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden",
|
||||
"ToastAuthorRemoveSuccess": "Autor entfernt",
|
||||
@@ -890,6 +943,8 @@
|
||||
"ToastBackupUploadSuccess": "Sicherung hochgeladen",
|
||||
"ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen",
|
||||
"ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich",
|
||||
"ToastBatchQuickMatchFailed": "Batch-Schnellabgleich fehlgeschlagen!",
|
||||
"ToastBatchQuickMatchStarted": "Batch-Schnellabgleich für {0} Bücher gestartet!",
|
||||
"ToastBatchUpdateFailed": "Stapelaktualisierung fehlgeschlagen",
|
||||
"ToastBatchUpdateSuccess": "Stapelaktualisierung erfolgreich",
|
||||
"ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden",
|
||||
@@ -901,9 +956,8 @@
|
||||
"ToastChaptersHaveErrors": "Kapitel sind fehlerhaft",
|
||||
"ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen",
|
||||
"ToastChaptersRemoved": "Kapitel entfernt",
|
||||
"ToastChaptersUpdated": "Kapitel aktualisiert",
|
||||
"ToastCollectionItemsAddFailed": "Das Hinzufügen von Element(en) zur Sammlung ist fehlgeschlagen",
|
||||
"ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt",
|
||||
"ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt",
|
||||
"ToastCollectionRemoveSuccess": "Sammlung entfernt",
|
||||
"ToastCollectionUpdateSuccess": "Sammlung aktualisiert",
|
||||
"ToastCoverUpdateFailed": "Cover-Update fehlgeschlagen",
|
||||
@@ -918,11 +972,14 @@
|
||||
"ToastEncodeCancelSucces": "Encoding abgebrochen",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "Warteschlange konnte nicht gelöscht werden",
|
||||
"ToastEpisodeDownloadQueueClearSuccess": "Warteschlange für Episoden-Downloads gelöscht",
|
||||
"ToastEpisodeUpdateSuccess": "{0} Episoden aktualisiert",
|
||||
"ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden",
|
||||
"ToastFailedToLoadData": "Daten laden fehlgeschlagen",
|
||||
"ToastFailedToMatch": "Fehler beim Abgleich",
|
||||
"ToastFailedToShare": "Fehler beim Teilen",
|
||||
"ToastFailedToUpdate": "Aktualisierung ist fehlgeschlagen",
|
||||
"ToastInvalidImageUrl": "Ungültiger Bild URL",
|
||||
"ToastInvalidMaxEpisodesToDownload": "Ungültige Max. Anzahl an Episoden zum Herunterladen",
|
||||
"ToastInvalidUrl": "Ungültiger URL",
|
||||
"ToastItemCoverUpdateSuccess": "Titelbild aktualisiert",
|
||||
"ToastItemDeletedFailed": "Fehler beim löschen des Artikels",
|
||||
@@ -941,14 +998,21 @@
|
||||
"ToastLibraryScanStarted": "Bibliotheksscan gestartet",
|
||||
"ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert",
|
||||
"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",
|
||||
"ToastNameRequired": "Name ist erforderlich",
|
||||
"ToastNewEpisodesFound": "{0} neue Episoden gefunden",
|
||||
"ToastNewUserCreatedFailed": "Fehler beim erstellen des Accounts: \"{ 0}\"",
|
||||
"ToastNewUserCreatedSuccess": "Neuer Account erstellt",
|
||||
"ToastNewUserLibraryError": "Mindestens eine Bibliothek muss ausgewählt werden",
|
||||
"ToastNewUserPasswordError": "Passwort erforderlich, nur der root Benutzer darf ein leeres Passwort haben",
|
||||
"ToastNewUserTagError": "Mindestens ein Tag muss ausgewählt sein",
|
||||
"ToastNewUserUsernameError": "Nutzername eingeben",
|
||||
"ToastNoNewEpisodesFound": "Keine neuen Episoden gefunden",
|
||||
"ToastNoUpdatesNecessary": "Keine Änderungen nötig",
|
||||
"ToastNotificationCreateFailed": "Fehler beim erstellen der Benachrichtig",
|
||||
"ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung",
|
||||
@@ -967,6 +1031,7 @@
|
||||
"ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast Feeds",
|
||||
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
|
||||
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
|
||||
"ToastProgressIsNotBeingSynced": "Fortschritt wird nicht synchronisiert, Wiedergabe wird neu gestartet",
|
||||
"ToastProviderCreatedFailed": "Fehler beim hinzufügen des Anbieters",
|
||||
"ToastProviderCreatedSuccess": "Neuer Anbieter hinzugefügt",
|
||||
"ToastProviderNameAndUrlRequired": "Name und URL notwendig",
|
||||
@@ -981,7 +1046,7 @@
|
||||
"ToastRenameFailed": "Umbenennen fehlgeschlagen",
|
||||
"ToastRescanFailed": "Erneut scannen fehlgeschlagen für {0}",
|
||||
"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",
|
||||
"ToastScanFailed": "Fehler beim scannen des Artikels der Bibliothek",
|
||||
"ToastSelectAtLeastOneUser": "Wähle mindestens einen Benutzer aus",
|
||||
@@ -993,6 +1058,7 @@
|
||||
"ToastSessionCloseFailed": "Fehler beim schließen der Sitzung",
|
||||
"ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden",
|
||||
"ToastSessionDeleteSuccess": "Sitzung gelöscht",
|
||||
"ToastSleepTimerDone": "Einschlaf-Timer aktiviert... zZzzZz",
|
||||
"ToastSlugMustChange": "URL-Schlüssel enthält ungültige Zeichen",
|
||||
"ToastSlugRequired": "URL-Schlüssel erforderlich",
|
||||
"ToastSocketConnected": "Verbindung zum WebSocket hergestellt",
|
||||
|
||||
@@ -88,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Save Tracklist",
|
||||
"ButtonScan": "Scan",
|
||||
"ButtonScanLibrary": "Scan Library",
|
||||
"ButtonScrollLeft": "Scroll Left",
|
||||
"ButtonScrollRight": "Scroll Right",
|
||||
"ButtonSearch": "Search",
|
||||
"ButtonSelectFolderPath": "Select Folder Path",
|
||||
"ButtonSeries": "Series",
|
||||
@@ -163,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "Update Notification",
|
||||
"HeaderNotifications": "Notifications",
|
||||
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
|
||||
"HeaderOpenListeningSessions": "Open Listening Sessions",
|
||||
"HeaderOpenRSSFeed": "Open RSS Feed",
|
||||
"HeaderOtherFiles": "Other Files",
|
||||
"HeaderPasswordAuthentication": "Password Authentication",
|
||||
@@ -189,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "Experimental Features",
|
||||
"HeaderSettingsGeneral": "General",
|
||||
"HeaderSettingsScanner": "Scanner",
|
||||
"HeaderSettingsWebClient": "Web Client",
|
||||
"HeaderSleepTimer": "Sleep Timer",
|
||||
"HeaderStatsLargestItems": "Largest Items",
|
||||
"HeaderStatsLongestItems": "Longest Items (hrs)",
|
||||
@@ -226,6 +230,7 @@
|
||||
"LabelAllUsersExcludingGuests": "All users excluding guests",
|
||||
"LabelAllUsersIncludingGuests": "All users including guests",
|
||||
"LabelAlreadyInYourLibrary": "Already in your library",
|
||||
"LabelApiToken": "API Token",
|
||||
"LabelAppend": "Append",
|
||||
"LabelAudioBitrate": "Audio Bitrate (e.g. 128k)",
|
||||
"LabelAudioChannels": "Audio Channels (1 or 2)",
|
||||
@@ -295,6 +300,7 @@
|
||||
"LabelDiscover": "Discover",
|
||||
"LabelDownload": "Download",
|
||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||
"LabelDownloadable": "Downloadable",
|
||||
"LabelDuration": "Duration",
|
||||
"LabelDurationComparisonExactMatch": "(exact match)",
|
||||
"LabelDurationComparisonLonger": "({0} longer)",
|
||||
@@ -463,12 +469,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.",
|
||||
"LabelOpenRSSFeed": "Open RSS Feed",
|
||||
"LabelOverwrite": "Overwrite",
|
||||
"LabelPaginationPageXOfY": "Page {0} of {1}",
|
||||
"LabelPassword": "Password",
|
||||
"LabelPath": "Path",
|
||||
"LabelPermanent": "Permanent",
|
||||
"LabelPermissionsAccessAllLibraries": "Can Access All Libraries",
|
||||
"LabelPermissionsAccessAllTags": "Can Access All Tags",
|
||||
"LabelPermissionsAccessExplicitContent": "Can Access Explicit Content",
|
||||
"LabelPermissionsCreateEreader": "Can Create Ereader",
|
||||
"LabelPermissionsDelete": "Can Delete",
|
||||
"LabelPermissionsDownload": "Can Download",
|
||||
"LabelPermissionsUpdate": "Can Update",
|
||||
@@ -538,6 +546,7 @@
|
||||
"LabelServerYearReview": "Server Year in Review ({0})",
|
||||
"LabelSetEbookAsPrimary": "Set as primary",
|
||||
"LabelSetEbookAsSupplementary": "Set as supplementary",
|
||||
"LabelSettingsAllowIframe": "Allow embedding in an iframe",
|
||||
"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",
|
||||
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
|
||||
@@ -559,6 +568,9 @@
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
|
||||
"LabelSettingsHomePageBookshelfView": "Home page 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",
|
||||
"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",
|
||||
@@ -577,6 +589,7 @@
|
||||
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders",
|
||||
"LabelSettingsTimeFormat": "Time Format",
|
||||
"LabelShare": "Share",
|
||||
"LabelShareDownloadableHelp": "Allows users with the share link to download a zip file of the library item.",
|
||||
"LabelShareOpen": "Share Open",
|
||||
"LabelShareURL": "Share URL",
|
||||
"LabelShowAll": "Show All",
|
||||
@@ -585,6 +598,8 @@
|
||||
"LabelSize": "Size",
|
||||
"LabelSleepTimer": "Sleep timer",
|
||||
"LabelSlug": "Slug",
|
||||
"LabelSortAscending": "Ascending",
|
||||
"LabelSortDescending": "Descending",
|
||||
"LabelStart": "Start",
|
||||
"LabelStartTime": "Start Time",
|
||||
"LabelStarted": "Started",
|
||||
@@ -656,6 +671,7 @@
|
||||
"LabelUpdateDetailsHelp": "Allow overwriting of existing details for the selected books when a match is located",
|
||||
"LabelUpdatedAt": "Updated At",
|
||||
"LabelUploaderDragAndDrop": "Drag & drop files or folders",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Drag & drop files",
|
||||
"LabelUploaderDropFiles": "Drop files",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Automatically fetch title, author, and series",
|
||||
"LabelUseAdvancedOptions": "Use Advanced Options",
|
||||
@@ -671,6 +687,8 @@
|
||||
"LabelViewPlayerSettings": "View player settings",
|
||||
"LabelViewQueue": "View player queue",
|
||||
"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",
|
||||
"LabelXBooks": "{0} books",
|
||||
"LabelXItems": "{0} items",
|
||||
@@ -740,6 +758,7 @@
|
||||
"MessageConfirmResetProgress": "Are you sure you want to reset your progress?",
|
||||
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?",
|
||||
"MessageConfirmUnlinkOpenId": "Are you sure you want to unlink this user from OpenID?",
|
||||
"MessageDaysListenedInTheLastYear": "{0} days listened in the last year",
|
||||
"MessageDownloadingEpisode": "Downloading episode",
|
||||
"MessageDragFilesIntoTrackOrder": "Drag files into correct track order",
|
||||
"MessageEmbedFailed": "Embed Failed!",
|
||||
@@ -755,7 +774,6 @@
|
||||
"MessageItemsSelected": "{0} Items Selected",
|
||||
"MessageItemsUpdated": "{0} Items Updated",
|
||||
"MessageJoinUsOn": "Join us on",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} listening sessions in the last year",
|
||||
"MessageLoading": "Loading...",
|
||||
"MessageLoadingFolders": "Loading folders...",
|
||||
"MessageLogsDescription": "Logs are stored in <code>/metadata/logs</code> as JSON files. Crash logs are stored in <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -943,8 +961,6 @@
|
||||
"ToastChaptersRemoved": "Chapters removed",
|
||||
"ToastChaptersUpdated": "Chapters updated",
|
||||
"ToastCollectionItemsAddFailed": "Item(s) added to collection failed",
|
||||
"ToastCollectionItemsAddSuccess": "Item(s) added to collection success",
|
||||
"ToastCollectionItemsRemoveSuccess": "Item(s) removed from collection",
|
||||
"ToastCollectionRemoveSuccess": "Collection removed",
|
||||
"ToastCollectionUpdateSuccess": "Collection updated",
|
||||
"ToastCoverUpdateFailed": "Cover update failed",
|
||||
|
||||
+57
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ButtonAdd": "Agregar",
|
||||
"ButtonAddChapters": "Agregar Capitulo",
|
||||
"ButtonAdd": "Agregaro",
|
||||
"ButtonAddChapters": "Agregar",
|
||||
"ButtonAddDevice": "Agregar Dispositivo",
|
||||
"ButtonAddLibrary": "Crear Biblioteca",
|
||||
"ButtonAddPodcasts": "Agregar Podcasts",
|
||||
@@ -71,8 +71,8 @@
|
||||
"ButtonQuickMatch": "Encontrar Rápido",
|
||||
"ButtonReScan": "Re-Escanear",
|
||||
"ButtonRead": "Leer",
|
||||
"ButtonReadLess": "Lea menos",
|
||||
"ButtonReadMore": "Lea mas",
|
||||
"ButtonReadLess": "Leer menos",
|
||||
"ButtonReadMore": "Leer más",
|
||||
"ButtonRefresh": "Refrecar",
|
||||
"ButtonRemove": "Remover",
|
||||
"ButtonRemoveAll": "Remover Todos",
|
||||
@@ -88,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Guardar Tracklist",
|
||||
"ButtonScan": "Escanear",
|
||||
"ButtonScanLibrary": "Escanear Biblioteca",
|
||||
"ButtonScrollLeft": "Desplazarse hacia la izquierda",
|
||||
"ButtonScrollRight": "Desplazarse hacia la derecha",
|
||||
"ButtonSearch": "Buscar",
|
||||
"ButtonSelectFolderPath": "Seleccionar Ruta de Carpeta",
|
||||
"ButtonSeries": "Series",
|
||||
@@ -163,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "Notificación de actualización",
|
||||
"HeaderNotifications": "Notificaciones",
|
||||
"HeaderOpenIDConnectAuthentication": "Autenticación OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "Sesiones públicas de escucha",
|
||||
"HeaderOpenRSSFeed": "Abrir fuente RSS",
|
||||
"HeaderOtherFiles": "Otros Archivos",
|
||||
"HeaderPasswordAuthentication": "Autenticación por contraseña",
|
||||
@@ -189,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "Funciones Experimentales",
|
||||
"HeaderSettingsGeneral": "General",
|
||||
"HeaderSettingsScanner": "Escáner",
|
||||
"HeaderSettingsWebClient": "Cliente web",
|
||||
"HeaderSleepTimer": "Temporizador de apagado",
|
||||
"HeaderStatsLargestItems": "Artículos mas Grandes",
|
||||
"HeaderStatsLongestItems": "Artículos mas Largos (h)",
|
||||
@@ -219,13 +223,14 @@
|
||||
"LabelAddToPlaylist": "Añadido a la lista de reproducción",
|
||||
"LabelAddToPlaylistBatch": "Se Añadieron {0} Artículos a la Lista de Reproducción",
|
||||
"LabelAddedAt": "Añadido",
|
||||
"LabelAddedDate": "Añadido {0}",
|
||||
"LabelAddedDate": "{0} Añadido",
|
||||
"LabelAdminUsersOnly": "Solamente usuarios administradores",
|
||||
"LabelAll": "Todos",
|
||||
"LabelAllUsers": "Todos los Usuarios",
|
||||
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
|
||||
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
|
||||
"LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca",
|
||||
"LabelApiToken": "Token de la API",
|
||||
"LabelAppend": "Adjuntar",
|
||||
"LabelAudioBitrate": "Tasa de bits del audio (por ejemplo, 128k)",
|
||||
"LabelAudioChannels": "Canales de audio (1 o 2)",
|
||||
@@ -251,6 +256,7 @@
|
||||
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
|
||||
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
|
||||
"LabelBitrate": "Tasa de bits",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "Libros",
|
||||
"LabelButtonText": "Texto del botón",
|
||||
"LabelByAuthor": "por {0}",
|
||||
@@ -329,6 +335,7 @@
|
||||
"LabelEpisodeType": "Tipo de Episodio",
|
||||
"LabelEpisodeUrlFromRssFeed": "URL del episodio del feed RSS",
|
||||
"LabelEpisodes": "Episodios",
|
||||
"LabelEpisodic": "Episodios",
|
||||
"LabelExample": "Ejemplo",
|
||||
"LabelExpandSeries": "Ampliar serie",
|
||||
"LabelExpandSubSeries": "Expandir la subserie",
|
||||
@@ -413,6 +420,9 @@
|
||||
"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",
|
||||
"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",
|
||||
"LabelMediaType": "Tipo de multimedia",
|
||||
"LabelMetaTag": "Metaetiqueta",
|
||||
@@ -458,12 +468,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.",
|
||||
"LabelOpenRSSFeed": "Abrir Fuente RSS",
|
||||
"LabelOverwrite": "Sobrescribir",
|
||||
"LabelPaginationPageXOfY": "Página {0} de {1}",
|
||||
"LabelPassword": "Contraseña",
|
||||
"LabelPath": "Ruta de carpeta",
|
||||
"LabelPermanent": "Permanente",
|
||||
"LabelPermissionsAccessAllLibraries": "Puede Accesar a Todas las bibliotecas",
|
||||
"LabelPermissionsAccessAllTags": "Pueda Accesar a Todas las Etiquetas",
|
||||
"LabelPermissionsAccessExplicitContent": "Puede Accesar a Contenido Explicito",
|
||||
"LabelPermissionsCreateEreader": "Puede crear un gestor de proyectos",
|
||||
"LabelPermissionsDelete": "Puede Eliminar",
|
||||
"LabelPermissionsDownload": "Puede Descargar",
|
||||
"LabelPermissionsUpdate": "Puede Actualizar",
|
||||
@@ -508,18 +520,24 @@
|
||||
"LabelRedo": "Rehacer",
|
||||
"LabelRegion": "Región",
|
||||
"LabelReleaseDate": "Fecha de Estreno",
|
||||
"LabelRemoveAllMetadataAbs": "Eliminar todos los archivos metadata.abs",
|
||||
"LabelRemoveAllMetadataJson": "Eliminar todos los archivos metadata.json",
|
||||
"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",
|
||||
"LabelSearchTerm": "Buscar Termino",
|
||||
"LabelSearchTitle": "Buscar Titulo",
|
||||
"LabelSearchTitleOrASIN": "Buscar Título o ASIN",
|
||||
"LabelSeason": "Temporada",
|
||||
"LabelSeasonNumber": "Sesión #{0}",
|
||||
"LabelSelectAll": "Seleccionar todo",
|
||||
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
|
||||
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
|
||||
"LabelSelectUsers": "Seleccionar usuarios",
|
||||
"LabelSendEbookToDevice": "Enviar Ebook a...",
|
||||
"LabelSequence": "Secuencia",
|
||||
"LabelSerial": "Serial",
|
||||
"LabelSeries": "Series",
|
||||
"LabelSeriesName": "Nombre de la Serie",
|
||||
"LabelSeriesProgress": "Progreso de la Serie",
|
||||
@@ -527,6 +545,7 @@
|
||||
"LabelServerYearReview": "Resumen del año del servidor ({0})",
|
||||
"LabelSetEbookAsPrimary": "Establecer como primario",
|
||||
"LabelSetEbookAsSupplementary": "Establecer como suplementario",
|
||||
"LabelSettingsAllowIframe": "Permitir incrustación en un iframe",
|
||||
"LabelSettingsAudiobooksOnly": "Sólo Audiolibros",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "Al activar esta opción se ignorarán los archivos de ebook a menos de que estén dentro de la carpeta de un audiolibro, en cuyo caso se marcarán como ebooks suplementarios",
|
||||
"LabelSettingsBookshelfViewHelp": "Diseño Esqueuomorfo con Estantes de Madera",
|
||||
@@ -548,6 +567,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.",
|
||||
"LabelSettingsHomePageBookshelfView": "Usar la vista de librero en la página principal",
|
||||
"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",
|
||||
"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",
|
||||
@@ -574,6 +596,8 @@
|
||||
"LabelSize": "Tamaño",
|
||||
"LabelSleepTimer": "Temporizador de apagado",
|
||||
"LabelSlug": "Slug",
|
||||
"LabelSortAscending": "Ascendente",
|
||||
"LabelSortDescending": "Descendente",
|
||||
"LabelStart": "Iniciar",
|
||||
"LabelStartTime": "Tiempo de Inicio",
|
||||
"LabelStarted": "Iniciado",
|
||||
@@ -612,6 +636,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} minutos",
|
||||
"LabelTimeDurationXSeconds": "{0} segundos",
|
||||
"LabelTimeInMinutes": "Tiempo en minutos",
|
||||
"LabelTimeLeft": "Quedan {0}",
|
||||
"LabelTimeListened": "Tiempo Escuchando",
|
||||
"LabelTimeListenedToday": "Tiempo Escuchando Hoy",
|
||||
"LabelTimeRemaining": "{0} restante",
|
||||
@@ -632,6 +657,7 @@
|
||||
"LabelTracksMultiTrack": "Varias pistas",
|
||||
"LabelTracksNone": "Ninguna pista",
|
||||
"LabelTracksSingleTrack": "Una pista",
|
||||
"LabelTrailer": "Tráiler",
|
||||
"LabelType": "Tipo",
|
||||
"LabelUnabridged": "No Abreviado",
|
||||
"LabelUndo": "Deshacer",
|
||||
@@ -643,11 +669,13 @@
|
||||
"LabelUpdateDetailsHelp": "Permitir sobrescribir detalles existentes de los libros seleccionados cuando sean encontrados",
|
||||
"LabelUpdatedAt": "Actualizado En",
|
||||
"LabelUploaderDragAndDrop": "Arrastre y suelte archivos o carpetas",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Arrastrar y soltar archivos",
|
||||
"LabelUploaderDropFiles": "Suelte los Archivos",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Buscar título, autor y series automáticamente",
|
||||
"LabelUseAdvancedOptions": "Usar opciones avanzadas",
|
||||
"LabelUseChapterTrack": "Usar pista por capitulo",
|
||||
"LabelUseFullTrack": "Usar pista completa",
|
||||
"LabelUseZeroForUnlimited": "Utilice 0 para ilimitado",
|
||||
"LabelUser": "Usuario",
|
||||
"LabelUsername": "Nombre de Usuario",
|
||||
"LabelValue": "Valor",
|
||||
@@ -657,11 +685,13 @@
|
||||
"LabelViewPlayerSettings": "Ver los ajustes del reproductor",
|
||||
"LabelViewQueue": "Ver Fila del Reproductor",
|
||||
"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",
|
||||
"LabelXBooks": "{0} libros",
|
||||
"LabelXItems": "{0} elementos",
|
||||
"LabelYearReviewHide": "Ocultar Year in Review",
|
||||
"LabelYearReviewShow": "Ver Year in Review",
|
||||
"LabelYearReviewHide": "Ocultar Resumen del año",
|
||||
"LabelYearReviewShow": "Resumen del año",
|
||||
"LabelYourAudiobookDuration": "Duración de tu Audiolibro",
|
||||
"LabelYourBookmarks": "Tus Marcadores",
|
||||
"LabelYourPlaylists": "Tus Listas",
|
||||
@@ -706,6 +736,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é?",
|
||||
"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?",
|
||||
"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)?",
|
||||
"MessageConfirmRemoveAllChapters": "¿Está seguro de que desea remover todos los capitulos?",
|
||||
"MessageConfirmRemoveAuthor": "¿Está seguro de que desea remover el autor \"{0}\"?",
|
||||
@@ -713,6 +744,7 @@
|
||||
"MessageConfirmRemoveEpisode": "¿Está seguro de que desea remover el episodio \"{0}\"?",
|
||||
"MessageConfirmRemoveEpisodes": "¿Está seguro de que desea remover {0} episodios?",
|
||||
"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}\"?",
|
||||
"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?",
|
||||
@@ -739,7 +771,6 @@
|
||||
"MessageItemsSelected": "{0} Elementos Seleccionados",
|
||||
"MessageItemsUpdated": "{0} Elementos Actualizados",
|
||||
"MessageJoinUsOn": "Únetenos en",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} sesiones de escucha en el último año",
|
||||
"MessageLoading": "Cargando...",
|
||||
"MessageLoadingFolders": "Cargando archivos...",
|
||||
"MessageLogsDescription": "Logs son almacenados en <code>/metadata/logs</code> en archivos bajo formato JSON. Logs de fallos son almacenados en <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -756,7 +787,7 @@
|
||||
"MessageNoBackups": "Sin Respaldos",
|
||||
"MessageNoBookmarks": "Sin marcadores",
|
||||
"MessageNoChapters": "Sin capítulos",
|
||||
"MessageNoCollections": "Sin Colecciones",
|
||||
"MessageNoCollections": "Sin colecciones",
|
||||
"MessageNoCoversFound": "Ninguna Portada Encontrada",
|
||||
"MessageNoDescription": "Sin Descripción",
|
||||
"MessageNoDevices": "Sin dispositivos",
|
||||
@@ -793,6 +824,7 @@
|
||||
"MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS",
|
||||
"MessageQuickEmbedInProgress": "Integración rápida en proceso",
|
||||
"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.",
|
||||
"MessageRemoveChapter": "Remover capítulos",
|
||||
"MessageRemoveEpisodes": "Remover {0} episodio(s)",
|
||||
@@ -891,6 +923,7 @@
|
||||
"StatsYearInReview": "RESEÑA DEL AÑO",
|
||||
"ToastAccountUpdateSuccess": "Cuenta actualizada",
|
||||
"ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise",
|
||||
"ToastAsinRequired": "Se requiere ASIN",
|
||||
"ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor",
|
||||
"ToastAuthorNotFound": "No se encontró el autor \"{0}\"",
|
||||
"ToastAuthorRemoveSuccess": "Autor eliminado",
|
||||
@@ -910,6 +943,8 @@
|
||||
"ToastBackupUploadSuccess": "Respaldo cargado",
|
||||
"ToastBatchDeleteFailed": "Error al eliminar por lotes",
|
||||
"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",
|
||||
"ToastBatchUpdateSuccess": "Subida masiva exitosa",
|
||||
"ToastBookmarkCreateFailed": "Error al crear marcador",
|
||||
@@ -921,9 +956,8 @@
|
||||
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
|
||||
"ToastChaptersMustHaveTitles": "Los capítulos tienen que tener un título",
|
||||
"ToastChaptersRemoved": "Capítulos eliminados",
|
||||
"ToastChaptersUpdated": "Capítulos actualizados",
|
||||
"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",
|
||||
"ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección",
|
||||
"ToastCollectionRemoveSuccess": "Colección removida",
|
||||
"ToastCollectionUpdateSuccess": "Colección actualizada",
|
||||
"ToastCoverUpdateFailed": "Error al actualizar la cubierta",
|
||||
@@ -938,11 +972,14 @@
|
||||
"ToastEncodeCancelSucces": "Codificación cancelada",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "No se pudo borrar la cola",
|
||||
"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",
|
||||
"ToastFailedToLoadData": "Error al cargar data",
|
||||
"ToastFailedToMatch": "Error al emparejar",
|
||||
"ToastFailedToShare": "Error al compartir",
|
||||
"ToastFailedToUpdate": "Error al actualizar",
|
||||
"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",
|
||||
"ToastItemCoverUpdateSuccess": "Portada del elemento actualizada",
|
||||
"ToastItemDeletedFailed": "Error al eliminar el elemento",
|
||||
@@ -961,14 +998,21 @@
|
||||
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
|
||||
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
|
||||
"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",
|
||||
"ToastNameRequired": "Nombre obligatorio",
|
||||
"ToastNewEpisodesFound": "{0} nuevo(s) episodio(s) encontrado(s)",
|
||||
"ToastNewUserCreatedFailed": "Error al crear la cuenta: \"{0}\"",
|
||||
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
|
||||
"ToastNewUserLibraryError": "Debes seleccionar al menos una biblioteca",
|
||||
"ToastNewUserPasswordError": "Debes tener una contraseña, solo el usuario root puede estar sin contraseña",
|
||||
"ToastNewUserTagError": "Debes seleccionar al menos una etiqueta",
|
||||
"ToastNewUserUsernameError": "Introduce un nombre de usuario",
|
||||
"ToastNoNewEpisodesFound": "No se encontraron nuevos episodios",
|
||||
"ToastNoUpdatesNecessary": "No es necesario actualizar",
|
||||
"ToastNotificationCreateFailed": "Error al crear notificación",
|
||||
"ToastNotificationDeleteFailed": "Error al borrar la notificación",
|
||||
@@ -987,6 +1031,7 @@
|
||||
"ToastPodcastGetFeedFailed": "No se puede obtener el podcast",
|
||||
"ToastPodcastNoEpisodesInFeed": "No se han encontrado episodios en el feed del 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",
|
||||
"ToastProviderCreatedSuccess": "Nuevo proveedor añadido",
|
||||
"ToastProviderNameAndUrlRequired": "Nombre y Url obligatorios",
|
||||
@@ -1013,6 +1058,7 @@
|
||||
"ToastSessionCloseFailed": "Error al cerrar la sesión",
|
||||
"ToastSessionDeleteFailed": "Error al eliminar sesión",
|
||||
"ToastSessionDeleteSuccess": "Sesión eliminada",
|
||||
"ToastSleepTimerDone": "Temporizador de apagado automático activado... zZzzZz",
|
||||
"ToastSlugMustChange": "El slug contiene caracteres no válidos",
|
||||
"ToastSlugRequired": "Slug obligatorio",
|
||||
"ToastSocketConnected": "Socket conectado",
|
||||
|
||||
@@ -611,7 +611,6 @@
|
||||
"MessageItemsSelected": "{0} Valitud üksust",
|
||||
"MessageItemsUpdated": "{0} Üksust on uuendatud",
|
||||
"MessageJoinUsOn": "Liitu meiega",
|
||||
"MessageListeningSessionsInTheLastYear": "Kuulamissessioone viimase aasta jooksul: {0}",
|
||||
"MessageLoading": "Laadimine...",
|
||||
"MessageLoadingFolders": "Kaustade laadimine...",
|
||||
"MessageM4BFailed": "M4B ebaõnnestus!",
|
||||
@@ -713,7 +712,6 @@
|
||||
"ToastBookmarkUpdateSuccess": "Järjehoidja värskendatud",
|
||||
"ToastChaptersHaveErrors": "Peatükkidel on vigu",
|
||||
"ToastChaptersMustHaveTitles": "Peatükkidel peab olema pealkiri",
|
||||
"ToastCollectionItemsRemoveSuccess": "Üksus(ed) eemaldatud kogumist",
|
||||
"ToastCollectionRemoveSuccess": "Kogum eemaldatud",
|
||||
"ToastCollectionUpdateSuccess": "Kogum värskendatud",
|
||||
"ToastItemCoverUpdateSuccess": "Üksuse kaas värskendatud",
|
||||
|
||||
+57
-9
@@ -122,7 +122,7 @@
|
||||
"HeaderBackups": "Sauvegardes",
|
||||
"HeaderChangePassword": "Modifier le mot de passe",
|
||||
"HeaderChapters": "Chapitres",
|
||||
"HeaderChooseAFolder": "Choisir un dossier",
|
||||
"HeaderChooseAFolder": "Sélectionner un dossier",
|
||||
"HeaderCollection": "Collection",
|
||||
"HeaderCollectionItems": "Entrées de la collection",
|
||||
"HeaderCover": "Couverture",
|
||||
@@ -163,6 +163,7 @@
|
||||
"HeaderNotificationUpdate": "Mise à jour de la notification",
|
||||
"HeaderNotifications": "Notifications",
|
||||
"HeaderOpenIDConnectAuthentication": "Authentification via OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "Ouvrir les sessions d'écoutes",
|
||||
"HeaderOpenRSSFeed": "Ouvrir le flux RSS",
|
||||
"HeaderOtherFiles": "Autres fichiers",
|
||||
"HeaderPasswordAuthentication": "Authentification par mot de passe",
|
||||
@@ -180,6 +181,7 @@
|
||||
"HeaderRemoveEpisodes": "Suppression de {0} épisodes",
|
||||
"HeaderSavedMediaProgress": "Progression de la sauvegarde des médias",
|
||||
"HeaderSchedule": "Programmation",
|
||||
"HeaderScheduleEpisodeDownloads": "Programmer des téléchargements automatiques d'épisodes",
|
||||
"HeaderScheduleLibraryScans": "Analyse automatique de la bibliothèque",
|
||||
"HeaderSession": "Session",
|
||||
"HeaderSetBackupSchedule": "Activer la sauvegarde automatique",
|
||||
@@ -225,6 +227,7 @@
|
||||
"LabelAllUsersExcludingGuests": "Tous les utilisateurs à l’exception des invités",
|
||||
"LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités",
|
||||
"LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque",
|
||||
"LabelApiToken": "Token API",
|
||||
"LabelAppend": "Ajouter",
|
||||
"LabelAudioBitrate": "Débit audio (par exemple 128k)",
|
||||
"LabelAudioChannels": "Canaux audio (1 ou 2)",
|
||||
@@ -250,15 +253,18 @@
|
||||
"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.",
|
||||
"LabelBitrate": "Débit binaire",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "Livres",
|
||||
"LabelButtonText": "Texte du bouton",
|
||||
"LabelByAuthor": "par {0}",
|
||||
"LabelChangePassword": "Modifier le mot de passe",
|
||||
"LabelChannels": "Canaux",
|
||||
"LabelChapterCount": "{0} Chapitres",
|
||||
"LabelChapterTitle": "Titre du chapitre",
|
||||
"LabelChapters": "Chapitres",
|
||||
"LabelChaptersFound": "chapitres trouvés",
|
||||
"LabelClickForMoreInfo": "Cliquez ici pour plus d’informations",
|
||||
"LabelClickToUseCurrentValue": "Cliquez pour utiliser la valeur actuelle",
|
||||
"LabelClosePlayer": "Fermer le lecteur",
|
||||
"LabelCodec": "Codec",
|
||||
"LabelCollapseSeries": "Réduire les séries",
|
||||
@@ -304,7 +310,7 @@
|
||||
"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.",
|
||||
"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",
|
||||
"LabelEmbeddedCover": "Couverture du livre intégrée",
|
||||
"LabelEnable": "Activer",
|
||||
@@ -320,9 +326,13 @@
|
||||
"LabelEnd": "Fin",
|
||||
"LabelEndOfChapter": "Fin du chapitre",
|
||||
"LabelEpisode": "Épisode",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "Épisode non lié au flux RSS",
|
||||
"LabelEpisodeNumber": "Épisode n°{0}",
|
||||
"LabelEpisodeTitle": "Titre de l’épisode",
|
||||
"LabelEpisodeType": "Type de l’épisode",
|
||||
"LabelEpisodeUrlFromRssFeed": "URL de l’épisode à partir du flux RSS",
|
||||
"LabelEpisodes": "Épisodes",
|
||||
"LabelEpisodic": "Épisodique",
|
||||
"LabelExample": "Exemple",
|
||||
"LabelExpandSeries": "Développer la série",
|
||||
"LabelExpandSubSeries": "Développer les sous-séries",
|
||||
@@ -350,6 +360,7 @@
|
||||
"LabelFontScale": "Taille de la police de caractère",
|
||||
"LabelFontStrikethrough": "Barrer",
|
||||
"LabelFormat": "Format",
|
||||
"LabelFull": "Complet",
|
||||
"LabelGenre": "Genre",
|
||||
"LabelGenres": "Genres",
|
||||
"LabelHardDeleteFile": "Suppression du fichier",
|
||||
@@ -405,6 +416,10 @@
|
||||
"LabelLowestPriority": "Priorité la plus basse",
|
||||
"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",
|
||||
"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",
|
||||
"LabelMediaType": "Type de média",
|
||||
"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é.",
|
||||
"LabelOpenRSSFeed": "Ouvrir le flux RSS",
|
||||
"LabelOverwrite": "Écraser",
|
||||
"LabelPaginationPageXOfY": "Page {0} sur {1}",
|
||||
"LabelPassword": "Mot de passe",
|
||||
"LabelPath": "Chemin",
|
||||
"LabelPermanent": "Permanent",
|
||||
"LabelPermissionsAccessAllLibraries": "Peut accéder à toutes les bibliothèque",
|
||||
"LabelPermissionsAccessAllTags": "Peut accéder à toutes les étiquettes",
|
||||
"LabelPermissionsAccessExplicitContent": "Peut accéder au contenu restreint",
|
||||
"LabelPermissionsCreateEreader": "Peut créer une liseuse",
|
||||
"LabelPermissionsDelete": "Peut supprimer",
|
||||
"LabelPermissionsDownload": "Peut télécharger",
|
||||
"LabelPermissionsUpdate": "Peut mettre à jour",
|
||||
@@ -500,18 +517,24 @@
|
||||
"LabelRedo": "Refaire",
|
||||
"LabelRegion": "Région",
|
||||
"LabelReleaseDate": "Date de parution",
|
||||
"LabelRemoveAllMetadataAbs": "Supprimer tous les fichiers metadata.abs",
|
||||
"LabelRemoveAllMetadataJson": "Supprimer tous les fichiers metadata.json",
|
||||
"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",
|
||||
"LabelSearchTerm": "Terme de recherche",
|
||||
"LabelSearchTitle": "Titre de recherche",
|
||||
"LabelSearchTitleOrASIN": "Recherche du titre ou ASIN",
|
||||
"LabelSeason": "Saison",
|
||||
"LabelSeasonNumber": "Saison n°{0}",
|
||||
"LabelSelectAll": "Tout sélectionner",
|
||||
"LabelSelectAllEpisodes": "Sélectionner tous les épisodes",
|
||||
"LabelSelectEpisodesShowing": "Sélectionner {0} épisode(s) en cours",
|
||||
"LabelSelectUsers": "Sélectionner les utilisateurs",
|
||||
"LabelSendEbookToDevice": "Envoyer le livre numérique à…",
|
||||
"LabelSequence": "Séquence",
|
||||
"LabelSerial": "N° de série",
|
||||
"LabelSeries": "Séries",
|
||||
"LabelSeriesName": "Nom de la série",
|
||||
"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.",
|
||||
"LabelSettingsHomePageBookshelfView": "Utiliser la vue étagère sur la page d’accueil",
|
||||
"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 »",
|
||||
"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",
|
||||
@@ -566,6 +592,8 @@
|
||||
"LabelSize": "Taille",
|
||||
"LabelSleepTimer": "Minuterie de mise en veille",
|
||||
"LabelSlug": "Identifiant d’URL",
|
||||
"LabelSortAscending": "Croissant",
|
||||
"LabelSortDescending": "Décroissant",
|
||||
"LabelStart": "Démarrer",
|
||||
"LabelStartTime": "Heure de démarrage",
|
||||
"LabelStarted": "Démarré",
|
||||
@@ -604,6 +632,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} minutes",
|
||||
"LabelTimeDurationXSeconds": "{0} secondes",
|
||||
"LabelTimeInMinutes": "Temps en minutes",
|
||||
"LabelTimeLeft": "{0} restant",
|
||||
"LabelTimeListened": "Temps d’écoute",
|
||||
"LabelTimeListenedToday": "Nombres d’écoutes aujourd’hui",
|
||||
"LabelTimeRemaining": "{0} restantes",
|
||||
@@ -624,6 +653,7 @@
|
||||
"LabelTracksMultiTrack": "Piste multiple",
|
||||
"LabelTracksNone": "Aucune piste",
|
||||
"LabelTracksSingleTrack": "Piste simple",
|
||||
"LabelTrailer": "Bande-annonce",
|
||||
"LabelType": "Type",
|
||||
"LabelUnabridged": "Version intégrale",
|
||||
"LabelUndo": "Annuler",
|
||||
@@ -635,11 +665,13 @@
|
||||
"LabelUpdateDetailsHelp": "Autoriser la mise à jour des détails existants lorsqu’une correspondance est trouvée",
|
||||
"LabelUpdatedAt": "Mis à jour à",
|
||||
"LabelUploaderDragAndDrop": "Glisser et déposer des fichiers ou dossiers",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Glisser & déposer des fichiers",
|
||||
"LabelUploaderDropFiles": "Déposer des fichiers",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Récupérer automatiquement le titre, l’auteur et la série",
|
||||
"LabelUseAdvancedOptions": "Utiliser les options avancées",
|
||||
"LabelUseChapterTrack": "Utiliser la piste du chapitre",
|
||||
"LabelUseFullTrack": "Utiliser la piste complète",
|
||||
"LabelUseZeroForUnlimited": "0 pour illimité",
|
||||
"LabelUser": "Utilisateur",
|
||||
"LabelUsername": "Nom d’utilisateur",
|
||||
"LabelValue": "Valeur",
|
||||
@@ -686,7 +718,7 @@
|
||||
"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 ?",
|
||||
"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 ?",
|
||||
"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 ?",
|
||||
@@ -697,7 +729,8 @@
|
||||
"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 ?",
|
||||
"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 ?",
|
||||
"MessageConfirmRemoveAllChapters": "Êtes-vous sûr·e de vouloir supprimer tous les chapitres ?",
|
||||
"MessageConfirmRemoveAuthor": "Êtes-vous sûr·e de vouloir supprimer l’auteur « {0} » ?",
|
||||
@@ -705,6 +738,7 @@
|
||||
"MessageConfirmRemoveEpisode": "Êtes-vous sûr·e de vouloir supprimer l’épisode « {0} » ?",
|
||||
"MessageConfirmRemoveEpisodes": "Êtes-vous sûr·e de vouloir supprimer {0} épisodes ?",
|
||||
"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} » ?",
|
||||
"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 ?",
|
||||
@@ -731,7 +765,6 @@
|
||||
"MessageItemsSelected": "{0} éléments sélectionnés",
|
||||
"MessageItemsUpdated": "{0} éléments mis à jour",
|
||||
"MessageJoinUsOn": "Rejoignez-nous sur",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} sessions d’écoute l’an dernier",
|
||||
"MessageLoading": "Chargement…",
|
||||
"MessageLoadingFolders": "Chargement des dossiers…",
|
||||
"MessageLogsDescription": "Les journaux sont stockés dans <code>/metadata/logs</code> sous forme de fichiers JSON. Les journaux d’incidents sont stockés dans <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -785,6 +818,7 @@
|
||||
"MessagePodcastSearchField": "Saisissez le terme de recherche ou l'URL du flux RSS",
|
||||
"MessageQuickEmbedInProgress": "Intégration rapide en cours",
|
||||
"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é.",
|
||||
"MessageRemoveChapter": "Supprimer le chapitre",
|
||||
"MessageRemoveEpisodes": "Suppression de {0} épisode(s)",
|
||||
@@ -837,10 +871,10 @@
|
||||
"MessageTaskScanningFileChanges": "Analyse des modifications du fichier dans « {0} »",
|
||||
"MessageTaskScanningLibrary": "Analyse de la bibliothèque « {0} »",
|
||||
"MessageTaskTargetDirectoryNotWritable": "Le répertoire cible n’est pas accessible en écriture",
|
||||
"MessageThinking": "Je cherche…",
|
||||
"MessageThinking": "À la recherche de…",
|
||||
"MessageUploaderItemFailed": "Échec du téléversement",
|
||||
"MessageUploaderItemSuccess": "Téléversement effectué !",
|
||||
"MessageUploading": "Téléversement…",
|
||||
"MessageUploading": "Téléchargement…",
|
||||
"MessageValidCronExpression": "Expression cron valide",
|
||||
"MessageWatcherIsDisabledGlobally": "La surveillance est désactivée par un paramètre global du serveur",
|
||||
"MessageXLibraryIsEmpty": "La bibliothèque {0} est vide !",
|
||||
@@ -883,6 +917,7 @@
|
||||
"StatsYearInReview": "BILAN DE L’ANNÉE",
|
||||
"ToastAccountUpdateSuccess": "Compte mis à jour",
|
||||
"ToastAppriseUrlRequired": "Vous devez entrer une URL Apprise",
|
||||
"ToastAsinRequired": "ASIN requis",
|
||||
"ToastAuthorImageRemoveSuccess": "Image de l’auteur supprimée",
|
||||
"ToastAuthorNotFound": "Auteur \"{0}\" non trouvé",
|
||||
"ToastAuthorRemoveSuccess": "Auteur supprimé",
|
||||
@@ -902,6 +937,8 @@
|
||||
"ToastBackupUploadSuccess": "Sauvegarde téléversée",
|
||||
"ToastBatchDeleteFailed": "Échec de la suppression par lot",
|
||||
"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",
|
||||
"ToastBatchUpdateSuccess": "Mise à jour par lot terminée",
|
||||
"ToastBookmarkCreateFailed": "Échec de la création de signet",
|
||||
@@ -913,9 +950,8 @@
|
||||
"ToastChaptersHaveErrors": "Les chapitres contiennent des erreurs",
|
||||
"ToastChaptersMustHaveTitles": "Les chapitre doivent avoir un titre",
|
||||
"ToastChaptersRemoved": "Chapitres supprimés",
|
||||
"ToastChaptersUpdated": "Chapitres mis à jour",
|
||||
"ToastCollectionItemsAddFailed": "Échec de l’ajout de(s) élément(s) à la collection",
|
||||
"ToastCollectionItemsAddSuccess": "Ajout de(s) élément(s) à la collection réussi",
|
||||
"ToastCollectionItemsRemoveSuccess": "Élément(s) supprimé(s) de la collection",
|
||||
"ToastCollectionRemoveSuccess": "Collection supprimée",
|
||||
"ToastCollectionUpdateSuccess": "Collection mise à jour",
|
||||
"ToastCoverUpdateFailed": "Échec de la mise à jour de la couverture",
|
||||
@@ -930,11 +966,14 @@
|
||||
"ToastEncodeCancelSucces": "Encodage annulé",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "Échec de la suppression de la file d'attente",
|
||||
"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",
|
||||
"ToastFailedToLoadData": "Échec du chargement des données",
|
||||
"ToastFailedToMatch": "Échec de la correspondance",
|
||||
"ToastFailedToShare": "Échec du partage",
|
||||
"ToastFailedToUpdate": "Échec de la mise à jour",
|
||||
"ToastInvalidImageUrl": "URL de l'image invalide",
|
||||
"ToastInvalidMaxEpisodesToDownload": "Nombre maximum d’épisodes à télécharger non valide",
|
||||
"ToastInvalidUrl": "URL invalide",
|
||||
"ToastItemCoverUpdateSuccess": "Couverture mise à jour",
|
||||
"ToastItemDeletedFailed": "La suppression de l'élément à échouée",
|
||||
@@ -953,14 +992,21 @@
|
||||
"ToastLibraryScanStarted": "Analyse de la bibliothèque démarrée",
|
||||
"ToastLibraryUpdateSuccess": "Bibliothèque « {0} » mise à jour",
|
||||
"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",
|
||||
"ToastNameRequired": "Le nom est requis",
|
||||
"ToastNewEpisodesFound": "{0} nouveaux épisodes trouvés",
|
||||
"ToastNewUserCreatedFailed": "La création du compte à échouée : « {0} »",
|
||||
"ToastNewUserCreatedSuccess": "Nouveau compte créé",
|
||||
"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",
|
||||
"ToastNewUserTagError": "Au moins une étiquette est requise",
|
||||
"ToastNewUserUsernameError": "Entrez un nom d’utilisateur",
|
||||
"ToastNoNewEpisodesFound": "Aucun nouvel épisode trouvé",
|
||||
"ToastNoUpdatesNecessary": "Aucune mise à jour nécessaire",
|
||||
"ToastNotificationCreateFailed": "La création de la notification à échouée",
|
||||
"ToastNotificationDeleteFailed": "La suppression de la notification à échouée",
|
||||
@@ -979,6 +1025,7 @@
|
||||
"ToastPodcastGetFeedFailed": "Échec de la récupération du flux du podcast",
|
||||
"ToastPodcastNoEpisodesInFeed": "Aucun épisode trouvé dans le 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",
|
||||
"ToastProviderCreatedSuccess": "Nouveau fournisseur ajouté",
|
||||
"ToastProviderNameAndUrlRequired": "Nom et URL requis",
|
||||
@@ -1005,6 +1052,7 @@
|
||||
"ToastSessionCloseFailed": "Échec de la fermeture de la session",
|
||||
"ToastSessionDeleteFailed": "Échec de la suppression de session",
|
||||
"ToastSessionDeleteSuccess": "Session supprimée",
|
||||
"ToastSleepTimerDone": "Minuterie de mise en veille terminée… zZzzZz",
|
||||
"ToastSlugMustChange": "L’identifiant d’URL contient des caractères invalides",
|
||||
"ToastSlugRequired": "L’identifiant d’URL est requis",
|
||||
"ToastSocketConnected": "WebSocket connecté",
|
||||
|
||||
+26
-5
@@ -8,17 +8,18 @@
|
||||
"ButtonAddYourFirstLibrary": "הוסף את הספרייה הראשונה שלך",
|
||||
"ButtonApply": "החל",
|
||||
"ButtonApplyChapters": "החל פרקים",
|
||||
"ButtonAuthors": "יוצרים",
|
||||
"ButtonAuthors": "סופרים",
|
||||
"ButtonBack": "חזור",
|
||||
"ButtonBrowseForFolder": "עיין בתיקייה",
|
||||
"ButtonCancel": "בטל",
|
||||
"ButtonCancel": "ביטול",
|
||||
"ButtonCancelEncode": "בטל קידוד",
|
||||
"ButtonChangeRootPassword": "שנה סיסמת root",
|
||||
"ButtonCheckAndDownloadNewEpisodes": "בדוק והורד פרקים חדשים",
|
||||
"ButtonChooseAFolder": "בחר תיקייה",
|
||||
"ButtonChooseFiles": "בחר קבצים",
|
||||
"ButtonClearFilter": "נקה סינון",
|
||||
"ButtonCloseFeed": "סגור פיד",
|
||||
"ButtonCloseFeed": "סגור ערוץ",
|
||||
"ButtonCloseSession": "סגור סשן פתוח",
|
||||
"ButtonCollections": "אוספים",
|
||||
"ButtonConfigureScanner": "הגדר סורק",
|
||||
"ButtonCreate": "צור",
|
||||
@@ -28,6 +29,7 @@
|
||||
"ButtonEdit": "ערוך",
|
||||
"ButtonEditChapters": "ערוך פרקים",
|
||||
"ButtonEditPodcast": "ערוך פודקאסט",
|
||||
"ButtonEnable": "הפעל",
|
||||
"ButtonForceReScan": "סרוק מחדש בכוח",
|
||||
"ButtonFullPath": "נתיב מלא",
|
||||
"ButtonHide": "הסתר",
|
||||
@@ -46,19 +48,24 @@
|
||||
"ButtonNevermind": "לא משנה",
|
||||
"ButtonNext": "הבא",
|
||||
"ButtonNextChapter": "פרק הבא",
|
||||
"ButtonNextItemInQueue": "פריט הבא בתור",
|
||||
"ButtonOk": "אישור",
|
||||
"ButtonOpenFeed": "פתח פיד",
|
||||
"ButtonOpenManager": "פתח מנהל",
|
||||
"ButtonPause": "השהה",
|
||||
"ButtonPlay": "נגן",
|
||||
"ButtonPlayAll": "נגן הכל",
|
||||
"ButtonPlaying": "מנגן",
|
||||
"ButtonPlaylists": "רשימות השמעה",
|
||||
"ButtonPrevious": "קודם",
|
||||
"ButtonPreviousChapter": "פרק קודם",
|
||||
"ButtonProbeAudioFile": "בדוק קובץ אודיו",
|
||||
"ButtonPurgeAllCache": "נקה את כל המטמון",
|
||||
"ButtonPurgeItemsCache": "נקה את מטמון הפריטים",
|
||||
"ButtonQueueAddItem": "הוסף לתור",
|
||||
"ButtonQueueRemoveItem": "הסר מהתור",
|
||||
"ButtonQuickEmbed": "הטמעה מהירה",
|
||||
"ButtonQuickEmbedMetadata": "הטמעת מטא נתונים מהירה",
|
||||
"ButtonQuickMatch": "התאמה מהירה",
|
||||
"ButtonReScan": "סרוק מחדש",
|
||||
"ButtonRead": "קרא",
|
||||
@@ -88,8 +95,10 @@
|
||||
"ButtonShow": "הצג",
|
||||
"ButtonStartM4BEncode": "התחל קידוד M4B",
|
||||
"ButtonStartMetadataEmbed": "התחל הטמעת מטא-נתונים",
|
||||
"ButtonStats": "סטטיסטיקות",
|
||||
"ButtonSubmit": "שלח",
|
||||
"ButtonTest": "בדיקה",
|
||||
"ButtonUnlinkOpenId": "נתק OpenID",
|
||||
"ButtonUpload": "העלה",
|
||||
"ButtonUploadBackup": "העלה גיבוי",
|
||||
"ButtonUploadCover": "העלה כריכה",
|
||||
@@ -102,6 +111,7 @@
|
||||
"ErrorUploadFetchMetadataNoResults": "לא ניתן לשלוף מטא-נתונים - נסה לעדכן כותרת ו/או יוצר",
|
||||
"ErrorUploadLacksTitle": "חובה לתת כותרת",
|
||||
"HeaderAccount": "חשבון",
|
||||
"HeaderAddCustomMetadataProvider": "הוסף ספק מטא-נתונים מותאם אישית",
|
||||
"HeaderAdvanced": "מתקדם",
|
||||
"HeaderAppriseNotificationSettings": "הגדרות התראות של Apprise",
|
||||
"HeaderAudioTracks": "רצועות קול",
|
||||
@@ -147,13 +157,17 @@
|
||||
"HeaderMetadataToEmbed": "מטא-נתונים להטמעה",
|
||||
"HeaderNewAccount": "חשבון חדש",
|
||||
"HeaderNewLibrary": "ספרייה חדשה",
|
||||
"HeaderNotificationCreate": "צור התראה",
|
||||
"HeaderNotificationUpdate": "עדכון התראה",
|
||||
"HeaderNotifications": "התראות",
|
||||
"HeaderOpenIDConnectAuthentication": "אימות OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "פתח הפעלות האזנה",
|
||||
"HeaderOpenRSSFeed": "פתח ערוץ RSS",
|
||||
"HeaderOtherFiles": "קבצים אחרים",
|
||||
"HeaderPasswordAuthentication": "אימות סיסמה",
|
||||
"HeaderPermissions": "הרשאות",
|
||||
"HeaderPlayerQueue": "תור ניגון",
|
||||
"HeaderPlayerSettings": "הגדרות נגן",
|
||||
"HeaderPlaylist": "רשימת השמעה",
|
||||
"HeaderPlaylistItems": "פריטי רשימת השמעה",
|
||||
"HeaderPodcastsToAdd": "פודקאסטים להוספה",
|
||||
@@ -165,6 +179,7 @@
|
||||
"HeaderRemoveEpisodes": "הסר {0} פרקים",
|
||||
"HeaderSavedMediaProgress": "התקדמות מדיה שמורה",
|
||||
"HeaderSchedule": "תיזמון",
|
||||
"HeaderScheduleEpisodeDownloads": "תזמן הורדת פרקים אוטומטית",
|
||||
"HeaderScheduleLibraryScans": "קבע סריקות ספרייה אוטומטיות",
|
||||
"HeaderSession": "הפעלה",
|
||||
"HeaderSetBackupSchedule": "קבע לוח זמנים לגיבוי",
|
||||
@@ -190,6 +205,9 @@
|
||||
"HeaderYearReview": "שנת {0} בסקירה",
|
||||
"HeaderYourStats": "הסטטיסטיקות שלך",
|
||||
"LabelAbridged": "מקוצר",
|
||||
"LabelAbridgedChecked": "מקוצר (מסומן)",
|
||||
"LabelAbridgedUnchecked": "בלתי מקוצר (לא מסומן)",
|
||||
"LabelAccessibleBy": "נגיש על ידי",
|
||||
"LabelAccountType": "סוג חשבון",
|
||||
"LabelAccountTypeAdmin": "מנהל",
|
||||
"LabelAccountTypeGuest": "אורח",
|
||||
@@ -200,13 +218,18 @@
|
||||
"LabelAddToPlaylist": "הוסף לרשימת השמעה",
|
||||
"LabelAddToPlaylistBatch": "הוסף {0} פריטים לרשימת השמעה",
|
||||
"LabelAddedAt": "נוסף בתאריך",
|
||||
"LabelAddedDate": "נוסף ב-{0}",
|
||||
"LabelAdminUsersOnly": "רק מנהלים",
|
||||
"LabelAll": "הכל",
|
||||
"LabelAllUsers": "כל המשתמשים",
|
||||
"LabelAllUsersExcludingGuests": "כל המשתמשים, ללא אורחים",
|
||||
"LabelAllUsersIncludingGuests": "כל המשתמשים כולל אורחים",
|
||||
"LabelAlreadyInYourLibrary": "כבר קיים בספרייה שלך",
|
||||
"LabelApiToken": "טוקן API",
|
||||
"LabelAppend": "הוסף לסוף",
|
||||
"LabelAudioBitrate": "קצב סיביות (לדוגמא 128k)",
|
||||
"LabelAudioChannels": "ערוצי קול (1 או 2)",
|
||||
"LabelAudioCodec": "קידוד קול",
|
||||
"LabelAuthor": "יוצר",
|
||||
"LabelAuthorFirstLast": "יוצר (שם פרטי שם משפחה)",
|
||||
"LabelAuthorLastFirst": "יוצר (שם משפחה, שם פרטי)",
|
||||
@@ -619,7 +642,6 @@
|
||||
"MessageItemsSelected": "{0} פריטים נבחרו",
|
||||
"MessageItemsUpdated": "{0} פריטים עודכנו",
|
||||
"MessageJoinUsOn": "הצטרף אלינו ב-",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} מפגשי האזנה בשנה האחרונה",
|
||||
"MessageLoading": "טוען...",
|
||||
"MessageLoadingFolders": "טוען תיקיות...",
|
||||
"MessageM4BFailed": "M4B נכשל!",
|
||||
@@ -721,7 +743,6 @@
|
||||
"ToastBookmarkUpdateSuccess": "הסימניה עודכנה בהצלחה",
|
||||
"ToastChaptersHaveErrors": "פרקים מכילים שגיאות",
|
||||
"ToastChaptersMustHaveTitles": "פרקים חייבים לכלול כותרות",
|
||||
"ToastCollectionItemsRemoveSuccess": "הפריט(ים) הוסרו מהאוסף בהצלחה",
|
||||
"ToastCollectionRemoveSuccess": "האוסף הוסר בהצלחה",
|
||||
"ToastCollectionUpdateSuccess": "האוסף עודכן בהצלחה",
|
||||
"ToastItemCoverUpdateSuccess": "כריכת הפריט עודכנה בהצלחה",
|
||||
|
||||
+29
-15
@@ -88,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Spremi popis zvučnih zapisa",
|
||||
"ButtonScan": "Skeniraj",
|
||||
"ButtonScanLibrary": "Skeniraj knjižnicu",
|
||||
"ButtonScrollLeft": "Pomicanje lijevo",
|
||||
"ButtonScrollRight": "Pomicanje desno",
|
||||
"ButtonSearch": "Traži",
|
||||
"ButtonSelectFolderPath": "Odaberi putanju mape",
|
||||
"ButtonSeries": "Serijali",
|
||||
@@ -163,6 +165,7 @@
|
||||
"HeaderNotificationUpdate": "Ažuriraj obavijest",
|
||||
"HeaderNotifications": "Obavijesti",
|
||||
"HeaderOpenIDConnectAuthentication": "Prijava na OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "Otvorene sesije slušanja",
|
||||
"HeaderOpenRSSFeed": "Otvori RSS izvor",
|
||||
"HeaderOtherFiles": "Druge datoteke",
|
||||
"HeaderPasswordAuthentication": "Provjera autentičnosti zaporkom",
|
||||
@@ -189,6 +192,7 @@
|
||||
"HeaderSettingsExperimental": "Eksperimentalne značajke",
|
||||
"HeaderSettingsGeneral": "Općenito",
|
||||
"HeaderSettingsScanner": "Skener",
|
||||
"HeaderSettingsWebClient": "Web klijent",
|
||||
"HeaderSleepTimer": "Timer za spavanje",
|
||||
"HeaderStatsLargestItems": "Najveće stavke",
|
||||
"HeaderStatsLongestItems": "Najduže stavke (sati)",
|
||||
@@ -226,6 +230,7 @@
|
||||
"LabelAllUsersExcludingGuests": "Svi korisnici osim gostiju",
|
||||
"LabelAllUsersIncludingGuests": "Svi korisnici uključujući i goste",
|
||||
"LabelAlreadyInYourLibrary": "Već u vašoj knjižnici",
|
||||
"LabelApiToken": "API Token",
|
||||
"LabelAppend": "Pridodaj",
|
||||
"LabelAudioBitrate": "Kvaliteta zvučnog zapisa (npr. 128k)",
|
||||
"LabelAudioChannels": "Broj zvučnih kanala (1 ili 2)",
|
||||
@@ -252,9 +257,9 @@
|
||||
"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",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "knjiga/e",
|
||||
"LabelBooks": "Knjige",
|
||||
"LabelButtonText": "Tekst gumba",
|
||||
"LabelByAuthor": "po {0}",
|
||||
"LabelByAuthor": "autor: {0}",
|
||||
"LabelChangePassword": "Promijeni zaporku",
|
||||
"LabelChannels": "Kanali",
|
||||
"LabelChapterCount": "{0} Poglavlje/a",
|
||||
@@ -268,8 +273,8 @@
|
||||
"LabelCollapseSeries": "Serijale prikaži sažeto",
|
||||
"LabelCollapseSubSeries": "Podserijale prikaži sažeto",
|
||||
"LabelCollection": "Zbirka",
|
||||
"LabelCollections": "Zbirka/i",
|
||||
"LabelComplete": "Dovršeno",
|
||||
"LabelCollections": "Zbirke",
|
||||
"LabelComplete": "Potpuno",
|
||||
"LabelConfirmPassword": "Potvrda zaporke",
|
||||
"LabelContinueListening": "Nastavi slušati",
|
||||
"LabelContinueReading": "Nastavi čitati",
|
||||
@@ -358,6 +363,7 @@
|
||||
"LabelFontScale": "Veličina slova",
|
||||
"LabelFontStrikethrough": "Precrtano",
|
||||
"LabelFormat": "Format",
|
||||
"LabelFull": "Cijeli",
|
||||
"LabelGenre": "Žanr",
|
||||
"LabelGenres": "Žanrovi",
|
||||
"LabelHardDeleteFile": "Obriši datoteku zauvijek",
|
||||
@@ -462,12 +468,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.",
|
||||
"LabelOpenRSSFeed": "Otvori RSS Feed",
|
||||
"LabelOverwrite": "Prepiši",
|
||||
"LabelPaginationPageXOfY": "Stranica {0} od {1}",
|
||||
"LabelPassword": "Zaporka",
|
||||
"LabelPath": "Putanja",
|
||||
"LabelPermanent": "Trajno",
|
||||
"LabelPermissionsAccessAllLibraries": "Ima pristup svim knjižnicama",
|
||||
"LabelPermissionsAccessAllTags": "Ima pristup svim oznakama",
|
||||
"LabelPermissionsAccessExplicitContent": "Ima pristup eksplicitnom sadržaju",
|
||||
"LabelPermissionsCreateEreader": "Može stvoriti e-čitač",
|
||||
"LabelPermissionsDelete": "Smije brisati",
|
||||
"LabelPermissionsDownload": "Smije preuzimati",
|
||||
"LabelPermissionsUpdate": "Smije ažurirati",
|
||||
@@ -491,8 +499,8 @@
|
||||
"LabelPubDate": "Datum izdavanja",
|
||||
"LabelPublishYear": "Godina objavljivanja",
|
||||
"LabelPublishedDate": "Objavljeno {0}",
|
||||
"LabelPublishedDecade": "Desetljeće objavljivanja",
|
||||
"LabelPublishedDecades": "Desetljeća objavljivanja",
|
||||
"LabelPublishedDecade": "Desetljeće izdanja",
|
||||
"LabelPublishedDecades": "Desetljeća izdanja",
|
||||
"LabelPublisher": "Izdavač",
|
||||
"LabelPublishers": "Izdavači",
|
||||
"LabelRSSFeedCustomOwnerEmail": "Prilagođena adresa e-pošte vlasnika",
|
||||
@@ -527,16 +535,17 @@
|
||||
"LabelSelectAllEpisodes": "Označi sve nastavke",
|
||||
"LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka",
|
||||
"LabelSelectUsers": "Označi korisnike",
|
||||
"LabelSendEbookToDevice": "Pošalji e-knjigu",
|
||||
"LabelSendEbookToDevice": "Pošalji e-knjigu …",
|
||||
"LabelSequence": "Slijed",
|
||||
"LabelSerial": "Serijal",
|
||||
"LabelSeries": "Serijal/a",
|
||||
"LabelSeries": "Serijal",
|
||||
"LabelSeriesName": "Ime serijala",
|
||||
"LabelSeriesProgress": "Napredak u serijalu",
|
||||
"LabelServerLogLevel": "Razina zapisa poslužitelja",
|
||||
"LabelServerYearReview": "Godišnji pregled poslužitelja ({0})",
|
||||
"LabelSetEbookAsPrimary": "Postavi kao primarno",
|
||||
"LabelSetEbookAsSupplementary": "Postavi kao dopunsko",
|
||||
"LabelSettingsAllowIframe": "Omogući ugrađivanje u iframeu",
|
||||
"LabelSettingsAudiobooksOnly": "Samo zvučne knjige",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "Ako uključite ovu mogućnost, sustav će zanemariti datoteke e-knjiga ukoliko se ne nalaze u mapi zvučne knjige, gdje će se smatrati dopunskim e-knjigama",
|
||||
"LabelSettingsBookshelfViewHelp": "Skeumorfni dizajn sa drvenim policama",
|
||||
@@ -558,8 +567,11 @@
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
@@ -584,6 +596,8 @@
|
||||
"LabelSize": "Veličina",
|
||||
"LabelSleepTimer": "Timer za spavanje",
|
||||
"LabelSlug": "Slug",
|
||||
"LabelSortAscending": "Uzlazno",
|
||||
"LabelSortDescending": "Silazno",
|
||||
"LabelStart": "Početak",
|
||||
"LabelStartTime": "Vrijeme početka",
|
||||
"LabelStarted": "Započeto",
|
||||
@@ -639,7 +653,7 @@
|
||||
"LabelTotalTimeListened": "Sveukupno vrijeme slušanja",
|
||||
"LabelTrackFromFilename": "Naslov iz imena datoteke",
|
||||
"LabelTrackFromMetadata": "Naslov iz meta-podataka",
|
||||
"LabelTracks": "Naslovi",
|
||||
"LabelTracks": "Zvučni zapisi",
|
||||
"LabelTracksMultiTrack": "Više zvučnih zapisa",
|
||||
"LabelTracksNone": "Nema zapisa",
|
||||
"LabelTracksSingleTrack": "Jedan zvučni zapis",
|
||||
@@ -655,6 +669,7 @@
|
||||
"LabelUpdateDetailsHelp": "Dopusti prepisivanje postojećih podataka za odabrane knjige kada se prepoznaju",
|
||||
"LabelUpdatedAt": "Ažurirano",
|
||||
"LabelUploaderDragAndDrop": "Pritisni i prevuci datoteke ili mape",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Pritisni i prevuci datoteke",
|
||||
"LabelUploaderDropFiles": "Ispusti datoteke",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Automatski dohvati naslov, autora i serijal",
|
||||
"LabelUseAdvancedOptions": "Koristi se naprednim opcijama",
|
||||
@@ -670,6 +685,8 @@
|
||||
"LabelViewPlayerSettings": "Pogledaj postavke reproduktora",
|
||||
"LabelViewQueue": "Pogledaj redoslijed izvođenja reproduktora",
|
||||
"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",
|
||||
"LabelXBooks": "{0} knjiga",
|
||||
"LabelXItems": "{0} stavki",
|
||||
@@ -740,7 +757,7 @@
|
||||
"MessageConfirmSendEbookToDevice": "Sigurno želite poslati {0} e-knjiga/u \"{1}\" na uređaj \"{2}\"?",
|
||||
"MessageConfirmUnlinkOpenId": "Sigurno želite odspojiti ovog korisnika s OpenID-ja?",
|
||||
"MessageDownloadingEpisode": "Preuzimam nastavak",
|
||||
"MessageDragFilesIntoTrackOrder": "Ispravi redoslijed zapisa prevlačenje datoteka",
|
||||
"MessageDragFilesIntoTrackOrder": "Prevlačenjem datoteka složite pravilan redoslijed",
|
||||
"MessageEmbedFailed": "Ugrađivanje nije uspjelo!",
|
||||
"MessageEmbedFinished": "Ugrađivanje je dovršeno!",
|
||||
"MessageEmbedQueue": "Ugrađivanje meta-podataka dodano u red obrade ({0} u redu)",
|
||||
@@ -754,7 +771,6 @@
|
||||
"MessageItemsSelected": "{0} odabranih stavki",
|
||||
"MessageItemsUpdated": "{0} stavki ažurirano",
|
||||
"MessageJoinUsOn": "Pridruži nam se na",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} slušanja u prošloj godini",
|
||||
"MessageLoading": "Učitavam...",
|
||||
"MessageLoadingFolders": "Učitavam mape...",
|
||||
"MessageLogsDescription": "Zapisnici se čuvaju u <code>/metadata/logs</code> u obliku JSON datoteka. Zapisnici pada sustava čuvaju se u datoteci <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -805,7 +821,7 @@
|
||||
"MessagePlaylistCreateFromCollection": "Stvori popis za izvođenje od zbirke",
|
||||
"MessagePleaseWait": "Molimo pričekajte...",
|
||||
"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",
|
||||
"MessageQuickEmbedQueue": "Dodano u red za brzo ugrađivanje ({0} u redu izvođenja)",
|
||||
"MessageQuickMatchAllEpisodes": "Brzo prepoznavanje svih nastavaka",
|
||||
@@ -942,8 +958,6 @@
|
||||
"ToastChaptersRemoved": "Poglavlja uklonjena",
|
||||
"ToastChaptersUpdated": "Poglavlja su ažurirana",
|
||||
"ToastCollectionItemsAddFailed": "Neuspješno dodavanje stavki u zbirku",
|
||||
"ToastCollectionItemsAddSuccess": "Uspješno dodavanje stavki u zbirku",
|
||||
"ToastCollectionItemsRemoveSuccess": "Stavke izbrisane iz zbirke",
|
||||
"ToastCollectionRemoveSuccess": "Zbirka izbrisana",
|
||||
"ToastCollectionUpdateSuccess": "Zbirka ažurirana",
|
||||
"ToastCoverUpdateFailed": "Ažuriranje naslovnice nije uspjelo",
|
||||
|
||||
+233
-20
@@ -66,6 +66,7 @@
|
||||
"ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése",
|
||||
"ButtonQueueAddItem": "Hozzáadás a sorhoz",
|
||||
"ButtonQueueRemoveItem": "Eltávolítás a sorból",
|
||||
"ButtonQuickEmbed": "Gyors beágyazás",
|
||||
"ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása",
|
||||
"ButtonQuickMatch": "Gyors egyeztetés",
|
||||
"ButtonReScan": "Újraszkennelés",
|
||||
@@ -87,6 +88,8 @@
|
||||
"ButtonSaveTracklist": "Sávlista mentése",
|
||||
"ButtonScan": "Szkennelés",
|
||||
"ButtonScanLibrary": "Könyvtár szkennelése",
|
||||
"ButtonScrollLeft": "Balra görgetés",
|
||||
"ButtonScrollRight": "Jobbra görgetés",
|
||||
"ButtonSearch": "Keresés",
|
||||
"ButtonSelectFolderPath": "Mappa útvonalának kiválasztása",
|
||||
"ButtonSeries": "Sorozatok",
|
||||
@@ -179,6 +182,7 @@
|
||||
"HeaderRemoveEpisodes": "{0} epizód eltávolítása",
|
||||
"HeaderSavedMediaProgress": "Mentett médialejátszási állapot",
|
||||
"HeaderSchedule": "Ütemezés",
|
||||
"HeaderScheduleEpisodeDownloads": "Automatikus epizódletöltés ütemezése",
|
||||
"HeaderScheduleLibraryScans": "Könyvtárak automatikus szkennelésének ütemezése",
|
||||
"HeaderSession": "Munkamenet",
|
||||
"HeaderSetBackupSchedule": "Biztonsági másolatok ütemezésének beállítása",
|
||||
@@ -187,13 +191,14 @@
|
||||
"HeaderSettingsExperimental": "Kísérleti funkciók",
|
||||
"HeaderSettingsGeneral": "Általános",
|
||||
"HeaderSettingsScanner": "Szkenner",
|
||||
"HeaderSettingsWebClient": "Webkliens",
|
||||
"HeaderSleepTimer": "Alvásidőzítő",
|
||||
"HeaderStatsLargestItems": "Legnagyobb elemek",
|
||||
"HeaderStatsLongestItems": "Leghosszabb elemek (órákban)",
|
||||
"HeaderStatsMinutesListeningChart": "Hallgatási grafikon percekben (az elmúlt 7 napból)",
|
||||
"HeaderStatsRecentSessions": "Legutóbbi munkamenetek",
|
||||
"HeaderStatsTop10Authors": "Top 10 szerzők",
|
||||
"HeaderStatsTop5Genres": "Top 5 műfajok",
|
||||
"HeaderStatsTop10Authors": "Top 10 szerző",
|
||||
"HeaderStatsTop5Genres": "Top 5 műfaj",
|
||||
"HeaderTableOfContents": "Tartalomjegyzék",
|
||||
"HeaderTools": "Eszközök",
|
||||
"HeaderUpdateAccount": "Fiók frissítése",
|
||||
@@ -201,7 +206,7 @@
|
||||
"HeaderUpdateDetails": "Részletek frissítése",
|
||||
"HeaderUpdateLibrary": "Könyvtár frissítése",
|
||||
"HeaderUsers": "Felhasználók",
|
||||
"HeaderYearReview": "{0} év áttekintése",
|
||||
"HeaderYearReview": "{0} év visszatekintése",
|
||||
"HeaderYourStats": "Saját statisztikák",
|
||||
"LabelAbridged": "Tömörített",
|
||||
"LabelAbridgedChecked": "Rövidített (ellenőrizve)",
|
||||
@@ -224,7 +229,11 @@
|
||||
"LabelAllUsersExcludingGuests": "Minden felhasználó, vendégek kivételével",
|
||||
"LabelAllUsersIncludingGuests": "Minden felhasználó, beleértve a vendégeket is",
|
||||
"LabelAlreadyInYourLibrary": "Már a könyvtárában van",
|
||||
"LabelApiToken": "API Token",
|
||||
"LabelAppend": "Hozzáfűzés",
|
||||
"LabelAudioBitrate": "Audió bitráta (pl.128k)",
|
||||
"LabelAudioChannels": "Audió csatorna (1 vagy 2)",
|
||||
"LabelAudioCodec": "Audio Codec",
|
||||
"LabelAuthor": "Szerző",
|
||||
"LabelAuthorFirstLast": "Szerző (Keresztnév Vezetéknév)",
|
||||
"LabelAuthorLastFirst": "Szerző (Vezetéknév, Keresztnév)",
|
||||
@@ -237,6 +246,7 @@
|
||||
"LabelAutoRegister": "Automatikus regisztráció",
|
||||
"LabelAutoRegisterDescription": "Új felhasználók automatikus létrehozása bejelentkezés után",
|
||||
"LabelBackToUser": "Vissza a felhasználóhoz",
|
||||
"LabelBackupAudioFiles": "Audiófájlok biztonsági mentése",
|
||||
"LabelBackupLocation": "Biztonsági másolat helye",
|
||||
"LabelBackupsEnableAutomaticBackups": "Automatikus biztonsági másolatok engedélyezése",
|
||||
"LabelBackupsEnableAutomaticBackupsHelp": "Biztonsági másolatok mentése a /metadata/backups mappába",
|
||||
@@ -245,15 +255,18 @@
|
||||
"LabelBackupsNumberToKeep": "Megtartandó biztonsági másolatok száma",
|
||||
"LabelBackupsNumberToKeepHelp": "Egyszerre csak 1 biztonsági másolat kerül eltávolításra, tehát ha már több biztonsági másolat van, mint ez a szám, akkor manuálisan kell eltávolítani őket.",
|
||||
"LabelBitrate": "Bitráta",
|
||||
"LabelBonus": "Bónusz",
|
||||
"LabelBooks": "Könyvek",
|
||||
"LabelButtonText": "Gomb szövege",
|
||||
"LabelByAuthor": "{} által",
|
||||
"LabelChangePassword": "Jelszó megváltoztatása",
|
||||
"LabelChannels": "Csatornák",
|
||||
"LabelChapterCount": "{0} Fejezet",
|
||||
"LabelChapterTitle": "Fejezet címe",
|
||||
"LabelChapters": "Fejezetek",
|
||||
"LabelChaptersFound": "fejezet található",
|
||||
"LabelClickForMoreInfo": "További információkért kattintson",
|
||||
"LabelClickToUseCurrentValue": "Kattintson az aktuális érték használatához",
|
||||
"LabelClosePlayer": "Lejátszó bezárása",
|
||||
"LabelCodec": "Kodek",
|
||||
"LabelCollapseSeries": "Sorozat összecsukása",
|
||||
@@ -303,16 +316,28 @@
|
||||
"LabelEmailSettingsTestAddress": "Teszt cím",
|
||||
"LabelEmbeddedCover": "Beágyazott borító",
|
||||
"LabelEnable": "Engedélyezés",
|
||||
"LabelEncodingBackupLocation": "Az eredeti hangfájlok biztonsági másolata a következő helyen lesz tárolva:",
|
||||
"LabelEncodingChaptersNotEmbedded": "A fejezetek nincsenek beágyazva a többsávos hangoskönyvekbe.",
|
||||
"LabelEncodingClearItemCache": "Győződjön meg róla, hogy rendszeresen tisztítja az elemek gyorsítótárát.",
|
||||
"LabelEncodingFinishedM4B": "A kész M4B a hangoskönyv mappádba kerül:",
|
||||
"LabelEncodingStartedNavigation": "Ha a feladat elindult, el lehet navigálni erről az oldalról.",
|
||||
"LabelEncodingTimeWarning": "A kódolás akár 30 percet is igénybe vehet.",
|
||||
"LabelEncodingWarningAdvancedSettings": "Figyelmeztetés: Ne frissítse ezeket a beállításokat, hacsak nem ismeri az ffmpeg kódolási beállításait.",
|
||||
"LabelEncodingWatcherDisabled": "Ha a figyelőt letiltotta, akkor ezt a hangoskönyvet utólag újra be kell olvasnia.",
|
||||
"LabelEnd": "Vége",
|
||||
"LabelEndOfChapter": "Fejezet vége",
|
||||
"LabelEpisode": "Epizód",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "Epizód nem kapcsolódik RSS hírcsatonához",
|
||||
"LabelEpisodeNumber": "Epizód #{0}",
|
||||
"LabelEpisodeTitle": "Epizód címe",
|
||||
"LabelEpisodeType": "Epizód típusa",
|
||||
"LabelEpisodeUrlFromRssFeed": "Epizód URL-címe az RSS hírcsatornából",
|
||||
"LabelEpisodes": "Epizódok",
|
||||
"LabelEpisodic": "Epizódikus",
|
||||
"LabelExample": "Példa",
|
||||
"LabelExpandSeries": "Sorozat kinyitása",
|
||||
"LabelExpandSubSeries": "Alsorozat kinyitása",
|
||||
"LabelExplicit": "Explicit",
|
||||
"LabelExplicit": "Szókimondó",
|
||||
"LabelExplicitChecked": "Explicit (ellenőrizve)",
|
||||
"LabelExplicitUnchecked": "Nem explicit (nem ellenőrzött)",
|
||||
"LabelExportOPML": "OPML exportálása",
|
||||
@@ -336,6 +361,7 @@
|
||||
"LabelFontScale": "Betűméret skála",
|
||||
"LabelFontStrikethrough": "Áthúzott",
|
||||
"LabelFormat": "Formátum",
|
||||
"LabelFull": "Teljes",
|
||||
"LabelGenre": "Műfaj",
|
||||
"LabelGenres": "Műfajok",
|
||||
"LabelHardDeleteFile": "Fájl végleges törlése",
|
||||
@@ -343,7 +369,7 @@
|
||||
"LabelHasSupplementaryEbook": "Van kiegészítő e-könyve",
|
||||
"LabelHideSubtitles": "Alcím elrejtése",
|
||||
"LabelHighestPriority": "Legmagasabb prioritás",
|
||||
"LabelHost": "Házigazda",
|
||||
"LabelHost": "Kiszolgáló",
|
||||
"LabelHour": "Óra",
|
||||
"LabelHours": "Órák",
|
||||
"LabelIcon": "Ikon",
|
||||
@@ -391,6 +417,10 @@
|
||||
"LabelLowestPriority": "Legalacsonyabb prioritás",
|
||||
"LabelMatchExistingUsersBy": "Meglévő felhasználók egyeztetése",
|
||||
"LabelMatchExistingUsersByDescription": "Meglévő felhasználók összekapcsolására használt. Egyszer összekapcsolva, a felhasználók egyedülálló azonosítóval lesznek egyeztetve az Ön SSO szolgáltatójától",
|
||||
"LabelMaxEpisodesToDownload": "Letölthető epizódok maximális száma. Használja a 0-t a korlátlan letöltéshez.",
|
||||
"LabelMaxEpisodesToDownloadPerCheck": "Ellenőrzésenként letölthető új epizódok maximális száma",
|
||||
"LabelMaxEpisodesToKeep": "Maximálisan megtartható epizódok száma",
|
||||
"LabelMaxEpisodesToKeepHelp": "A 0 érték nem állít be maximális korlátot. Az új epizód automatikus letöltése után ez a beállítás törli a legrégebbi epizódot, ha X epizódnál több van. Új letöltésenként csak 1 epizódot töröl.",
|
||||
"LabelMediaPlayer": "Médialejátszó",
|
||||
"LabelMediaType": "Média típus",
|
||||
"LabelMetaTag": "Meta címke",
|
||||
@@ -398,7 +428,7 @@
|
||||
"LabelMetadataOrderOfPrecedenceDescription": "A magasabb prioritású metaadat-források felülírják az alacsonyabb prioritásúakat",
|
||||
"LabelMetadataProvider": "Metaadat-szolgáltató",
|
||||
"LabelMinute": "Perc",
|
||||
"LabelMinutes": "Percek",
|
||||
"LabelMinutes": "Perc",
|
||||
"LabelMissing": "Hiányzó",
|
||||
"LabelMissingEbook": "Nincs e-könyve",
|
||||
"LabelMissingSupplementaryEbook": "Nincs kiegészítő e-könyve",
|
||||
@@ -433,20 +463,22 @@
|
||||
"LabelNumberOfEpisodes": "Epizódok száma",
|
||||
"LabelOpenIDAdvancedPermsClaimDescription": "Az OpenID-igény neve, amely a felhasználói műveletekre vonatkozó haladó jogosultságokat tartalmazza az alkalmazáson belül, és amely a nem adminisztrátori szerepkörökre vonatkozik (<b>ha konfigurálva van</b>). Ha az igény hiányzik a válaszból, az ABS-hez való hozzáférés megtagadásra kerül. Ha egyetlen opció hiányzik, azt <code>false</code>-ként fogja kezelni. Győződj meg arról, hogy az identitásszolgáltató igénye megfelel a várt struktúrának:",
|
||||
"LabelOpenIDClaims": "Hagyd üresen a következő opciókat, hogy letiltsd a haladó csoport- és jogosultság-hozzárendelést, ekkor automatikusan a ‘Felhasználó’ csoport kerül hozzárendelésre.",
|
||||
"LabelOpenIDGroupClaimDescription": "Az OpenID-igény neve, amely a felhasználó csoportjainak listáját tartalmazza. Általában groups néven hivatkoznak rá. Ha konfigurálva van, az alkalmazás automatikusan hozzárendeli a szerepköröket a felhasználó csoporttagságai alapján, feltéve, hogy ezek a csoportok az igényben kis- és nagybetűkre érzéketlenül ‘admin’, ‘user’ vagy ‘guest’ néven szerepelnek. Az igénynek egy listát kell tartalmaznia, és ha egy felhasználó több csoport tagja, az alkalmazás a legmagasabb szintű hozzáféréssel rendelkező szerepkört rendeli hozzá. Ha egyetlen csoport sem felel meg, a hozzáférés megtagadásra kerül.",
|
||||
"LabelOpenIDGroupClaimDescription": "Az OpenID-igény neve, amely a felhasználó csoportjainak listáját tartalmazza. Általában <code>groups<code> néven hivatkoznak rá. <b>Ha konfigurálva van<b>, az alkalmazás automatikusan hozzárendeli a szerepköröket a felhasználó csoporttagságai alapján, feltéve, hogy ezek a csoportok az igényben kis- és nagybetűkre érzéketlenül ‘admin’, ‘user’ vagy ‘guest’ néven szerepelnek. Az igénynek egy listát kell tartalmaznia, és ha egy felhasználó több csoport tagja, az alkalmazás a legmagasabb szintű hozzáféréssel rendelkező szerepkört rendeli hozzá. Ha egyetlen csoport sem felel meg, a hozzáférés megtagadásra kerül.",
|
||||
"LabelOpenRSSFeed": "RSS hírcsatorna megnyitása",
|
||||
"LabelOverwrite": "Felülírás",
|
||||
"LabelPaginationPageXOfY": "{0} oldal {1}-ból/ből",
|
||||
"LabelPassword": "Jelszó",
|
||||
"LabelPath": "Útvonal",
|
||||
"LabelPermanent": "Végleges",
|
||||
"LabelPermissionsAccessAllLibraries": "Hozzáférhet az összes könyvtárhoz",
|
||||
"LabelPermissionsAccessAllTags": "Hozzáférhet az összes címkéhez",
|
||||
"LabelPermissionsAccessExplicitContent": "Hozzáférhet explicit tartalomhoz",
|
||||
"LabelPermissionsCreateEreader": "Létrehozhat Ereader-t",
|
||||
"LabelPermissionsDelete": "Törölhet",
|
||||
"LabelPermissionsDownload": "Letölthet",
|
||||
"LabelPermissionsUpdate": "Frissíthet",
|
||||
"LabelPermissionsUpload": "Feltölthet",
|
||||
"LabelPersonalYearReview": "Az éved áttekintése ({0})",
|
||||
"LabelPersonalYearReview": "Az évvisszatekintésed ({0})",
|
||||
"LabelPhotoPathURL": "Fénykép útvonal/URL",
|
||||
"LabelPlayMethod": "Lejátszási módszer",
|
||||
"LabelPlayerChapterNumberMarker": "{0} a {1} -ből",
|
||||
@@ -465,6 +497,8 @@
|
||||
"LabelPubDate": "Kiadás dátuma",
|
||||
"LabelPublishYear": "Kiadás éve",
|
||||
"LabelPublishedDate": "Kiadva {0}",
|
||||
"LabelPublishedDecade": "Közzétett évtized",
|
||||
"LabelPublishedDecades": "Közzétett évtized",
|
||||
"LabelPublisher": "Kiadó",
|
||||
"LabelPublishers": "Kiadók",
|
||||
"LabelRSSFeedCustomOwnerEmail": "Egyéni tulajdonos e-mail",
|
||||
@@ -474,6 +508,7 @@
|
||||
"LabelRSSFeedSlug": "RSS hírcsatorna slug",
|
||||
"LabelRSSFeedURL": "RSS hírcsatorna URL",
|
||||
"LabelRandomly": "Véletlenszerűen",
|
||||
"LabelReAddSeriesToContinueListening": "Sorozat újbóli hozzáadása a folytatáshoz",
|
||||
"LabelRead": "Olvasás",
|
||||
"LabelReadAgain": "Újraolvasás",
|
||||
"LabelReadEbookWithoutProgress": "E-könyv olvasása haladás nélkül",
|
||||
@@ -483,12 +518,18 @@
|
||||
"LabelRedo": "Újra",
|
||||
"LabelRegion": "Régió",
|
||||
"LabelReleaseDate": "Megjelenés dátuma",
|
||||
"LabelRemoveAllMetadataAbs": "Az összes metadata.abs fájl eltávolítása",
|
||||
"LabelRemoveAllMetadataJson": "Az összes metadata.json fájl eltávolítása",
|
||||
"LabelRemoveCover": "Borító eltávolítása",
|
||||
"LabelRemoveMetadataFile": "Metaadatfájlok eltávolítása a könyvtár elemek mappáiból",
|
||||
"LabelRemoveMetadataFileHelp": "A metadata.json és metadata.abs fájlokat eltávolítása a {0} mappáidból.",
|
||||
"LabelRowsPerPage": "Sorok száma oldalanként",
|
||||
"LabelSearchTerm": "Keresési kifejezés",
|
||||
"LabelSearchTitle": "Cím keresése",
|
||||
"LabelSearchTitleOrASIN": "Cím vagy ASIN keresése",
|
||||
"LabelSeason": "Évad",
|
||||
"LabelSeasonNumber": "Évad #{0}",
|
||||
"LabelSelectAll": "Minden kiválasztása",
|
||||
"LabelSelectAllEpisodes": "Összes epizód kiválasztása",
|
||||
"LabelSelectEpisodesShowing": "Kiválasztás {0} megjelenített epizód",
|
||||
"LabelSelectUsers": "Felhasználók kiválasztása",
|
||||
@@ -497,8 +538,11 @@
|
||||
"LabelSeries": "Sorozat",
|
||||
"LabelSeriesName": "Sorozat neve",
|
||||
"LabelSeriesProgress": "Sorozat haladása",
|
||||
"LabelServerLogLevel": "Kiszolgáló naplózási szint",
|
||||
"LabelServerYearReview": "Szerver évvisszatekintés ({0})",
|
||||
"LabelSetEbookAsPrimary": "Beállítás elsődlegesként",
|
||||
"LabelSetEbookAsSupplementary": "Beállítás kiegészítőként",
|
||||
"LabelSettingsAllowIframe": "A beágyazás engedélyezése egy iframe-be",
|
||||
"LabelSettingsAudiobooksOnly": "Csak hangoskönyvek",
|
||||
"LabelSettingsAudiobooksOnlyHelp": "Ennek a beállításnak az engedélyezése figyelmen kívül hagyja az e-könyv fájlokat, kivéve, ha azok egy hangoskönyv mappában vannak, ebben az esetben kiegészítő e-könyvként lesznek beállítva",
|
||||
"LabelSettingsBookshelfViewHelp": "Skeuomorfikus dizájn fa polcokkal",
|
||||
@@ -510,6 +554,8 @@
|
||||
"LabelSettingsEnableWatcher": "Figyelő engedélyezése",
|
||||
"LabelSettingsEnableWatcherForLibrary": "Mappafigyelő engedélyezése a könyvtárban",
|
||||
"LabelSettingsEnableWatcherHelp": "Engedélyezi az automatikus elem hozzáadás/frissítés funkciót, amikor fájlváltozásokat észlel. *Szerver újraindítása szükséges",
|
||||
"LabelSettingsEpubsAllowScriptedContent": "Szkriptelt tartalmak engedélyezése epub-okban",
|
||||
"LabelSettingsEpubsAllowScriptedContentHelp": "Megengedi, hogy az epub fájlok szkripteket hajtsanak végre. Ezt a beállítást kikapcsolva ajánlott tartani, kivéve, ha megbízik az epub fájlok forrásában.",
|
||||
"LabelSettingsExperimentalFeatures": "Kísérleti funkciók",
|
||||
"LabelSettingsExperimentalFeaturesHelp": "Fejlesztés alatt álló funkciók, amelyek visszajelzésre és tesztelésre szorulnak. Kattintson a github megbeszélés megnyitásához.",
|
||||
"LabelSettingsFindCovers": "Borítók keresése",
|
||||
@@ -518,6 +564,11 @@
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "A csak egy könyvet tartalmazó sorozatok el lesznek rejtve a sorozatok oldalról és a kezdőlap polcairól.",
|
||||
"LabelSettingsHomePageBookshelfView": "Kezdőlap használja a könyvespolc nézetet",
|
||||
"LabelSettingsLibraryBookshelfView": "Könyvtár használja a könyvespolc nézetet",
|
||||
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Százalékos befejezettség nagyobb mint",
|
||||
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "A hátralévő idő kevesebb, mint (másodperc)",
|
||||
"LabelSettingsLibraryMarkAsFinishedWhen": "A médiaelem befejezettnek jelölése, ha",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Megelőző könyvek kihagyása a Sorozat folytatásában",
|
||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "A Sorozat folytatása kezdőlap polcán az első nem megkezdett könyv látható egy olyan sorozatban, amelynek legalább egy könyve befejeződött, és nincs folyamatban lévő rész. Ha engedélyezi ezt a beállítást, akkor a sorozatot a legvégső befejezett könyvtől folytatja az első el nem kezdett könyv helyett.",
|
||||
"LabelSettingsParseSubtitles": "Feliratok elemzése",
|
||||
"LabelSettingsParseSubtitlesHelp": "Feliratok kinyerése a hangoskönyv mappaneveiből.<br>A feliratnak el kell különülnie egy \" - \" jellel<br>például: \"Könyv címe - Egy felirat itt\" esetén a felirat \"Egy felirat itt\"",
|
||||
"LabelSettingsPreferMatchedMetadata": "Preferált egyeztetett metaadatok",
|
||||
@@ -533,10 +584,14 @@
|
||||
"LabelSettingsStoreMetadataWithItem": "Metaadatok tárolása az elemmel",
|
||||
"LabelSettingsStoreMetadataWithItemHelp": "Alapértelmezés szerint a metaadatfájlok a /metadata/items mappában vannak tárolva, ennek a beállításnak az engedélyezése a metaadatfájlokat a könyvtári elem mappáiban tárolja",
|
||||
"LabelSettingsTimeFormat": "Időformátum",
|
||||
"LabelShare": "Megosztás",
|
||||
"LabelShowAll": "Mindent mutat",
|
||||
"LabelShowSubtitles": "Felirat megjelenítése",
|
||||
"LabelSize": "Méret",
|
||||
"LabelSleepTimer": "Alvásidőzítő",
|
||||
"LabelSlug": "Rövid cím",
|
||||
"LabelSortAscending": "Emelkedő",
|
||||
"LabelSortDescending": "Csökkenő",
|
||||
"LabelStart": "Kezdés",
|
||||
"LabelStartTime": "Kezdési idő",
|
||||
"LabelStarted": "Elkezdődött",
|
||||
@@ -546,13 +601,13 @@
|
||||
"LabelStatsBestDay": "Legjobb nap",
|
||||
"LabelStatsDailyAverage": "Napi átlag",
|
||||
"LabelStatsDays": "Napok",
|
||||
"LabelStatsDaysListened": "Hallgatott napok",
|
||||
"LabelStatsDaysListened": "Napon hallgatva",
|
||||
"LabelStatsHours": "Órák",
|
||||
"LabelStatsInARow": "egymás után",
|
||||
"LabelStatsItemsFinished": "Befejezett elemek",
|
||||
"LabelStatsItemsFinished": "Befejezett elem",
|
||||
"LabelStatsItemsInLibrary": "Elemek a könyvtárban",
|
||||
"LabelStatsMinutes": "percek",
|
||||
"LabelStatsMinutesListening": "Hallgatási percek",
|
||||
"LabelStatsMinutes": "perc",
|
||||
"LabelStatsMinutesListening": "Hallgatási perc",
|
||||
"LabelStatsOverallDays": "Összes nap",
|
||||
"LabelStatsOverallHours": "Összes óra",
|
||||
"LabelStatsWeekListening": "Heti hallgatás",
|
||||
@@ -564,12 +619,18 @@
|
||||
"LabelTagsNotAccessibleToUser": "A felhasználó számára nem elérhető címkék",
|
||||
"LabelTasks": "Futó feladatok",
|
||||
"LabelTextEditorBulletedList": "Pontozott lista",
|
||||
"LabelTextEditorLink": "Hivatkozás",
|
||||
"LabelTextEditorNumberedList": "Számozott lista",
|
||||
"LabelTextEditorUnlink": "Link eltávolítása",
|
||||
"LabelTheme": "Téma",
|
||||
"LabelThemeDark": "Sötét",
|
||||
"LabelThemeLight": "Világos",
|
||||
"LabelTimeBase": "Időalap",
|
||||
"LabelTimeDurationXHours": "{0} óra",
|
||||
"LabelTimeDurationXMinutes": "{0} perc",
|
||||
"LabelTimeDurationXSeconds": "{0} másodperc",
|
||||
"LabelTimeInMinutes": "Idő percben",
|
||||
"LabelTimeLeft": "{0} maradt hátra",
|
||||
"LabelTimeListened": "Hallgatott idő",
|
||||
"LabelTimeListenedToday": "Ma hallgatott idő",
|
||||
"LabelTimeRemaining": "{0} maradt",
|
||||
@@ -577,6 +638,7 @@
|
||||
"LabelTitle": "Cím",
|
||||
"LabelToolsEmbedMetadata": "Metaadatok beágyazása",
|
||||
"LabelToolsEmbedMetadataDescription": "Metaadatok beágyazása az audiofájlokba, beleértve a borítóképet és a fejezeteket.",
|
||||
"LabelToolsM4bEncoder": "M4B kódoló",
|
||||
"LabelToolsMakeM4b": "M4B Hangoskönyv fájl készítése",
|
||||
"LabelToolsMakeM4bDescription": ".M4B hangoskönyv fájl generálása beágyazott metaadatokkal, borítóképpel és fejezetekkel.",
|
||||
"LabelToolsSplitM4b": "M4B felosztása MP3-ra",
|
||||
@@ -589,29 +651,41 @@
|
||||
"LabelTracksMultiTrack": "Többsávos",
|
||||
"LabelTracksNone": "Nincsenek sávok",
|
||||
"LabelTracksSingleTrack": "Egysávos",
|
||||
"LabelTrailer": "Előzetes",
|
||||
"LabelType": "Típus",
|
||||
"LabelUnabridged": "Nem tömörített",
|
||||
"LabelUndo": "Visszavonás",
|
||||
"LabelUnknown": "Ismeretlen",
|
||||
"LabelUnknownPublishDate": "Ismeretlen megjelenési dátum",
|
||||
"LabelUpdateCover": "Borító frissítése",
|
||||
"LabelUpdateCoverHelp": "Lehetővé teszi a meglévő borítók felülírását a kiválasztott könyveknél, amikor találatot talál",
|
||||
"LabelUpdateDetails": "Részletek frissítése",
|
||||
"LabelUpdateDetailsHelp": "Lehetővé teszi a meglévő részletek felülírását a kiválasztott könyveknél, amikor találatot talál",
|
||||
"LabelUpdatedAt": "Frissítve",
|
||||
"LabelUploaderDragAndDrop": "Fájlok vagy mappák húzása és elengedése",
|
||||
"LabelUploaderDragAndDropFilesOnly": "Fájlok húzása és elengedése",
|
||||
"LabelUploaderDropFiles": "Fájlok elengedése",
|
||||
"LabelUploaderItemFetchMetadataHelp": "Cím, szerző és sorozat automatikus lekérése",
|
||||
"LabelUseAdvancedOptions": "Haladó beállítások használata",
|
||||
"LabelUseChapterTrack": "Fejezetsáv használata",
|
||||
"LabelUseFullTrack": "Teljes sáv használata",
|
||||
"LabelUseZeroForUnlimited": "Használja a 0-t a korlátlan értékhez",
|
||||
"LabelUser": "Felhasználó",
|
||||
"LabelUsername": "Felhasználónév",
|
||||
"LabelValue": "Érték",
|
||||
"LabelVersion": "Verzió",
|
||||
"LabelViewBookmarks": "Könyvjelzők megtekintése",
|
||||
"LabelViewChapters": "Fejezetek megtekintése",
|
||||
"LabelViewPlayerSettings": "A lejátszó beállításainak megtekintése",
|
||||
"LabelViewQueue": "Lejátszó sor megtekintése",
|
||||
"LabelVolume": "Hangerő",
|
||||
"LabelWebRedirectURLsDescription": "Engedélyezze ezeket az URL-címeket az OAuth-szolgáltatóban, hogy a bejelentkezés után vissza lehessen irányítani a webes alkalmazáshoz:",
|
||||
"LabelWebRedirectURLsSubfolder": "Almappa átirányító URL-ek számára",
|
||||
"LabelWeekdaysToRun": "Futás napjai",
|
||||
"LabelXBooks": "{0} könyv",
|
||||
"LabelXItems": "{0} elem",
|
||||
"LabelYearReviewHide": "Az évvisszatekintés elrejtése",
|
||||
"LabelYearReviewShow": "Évvisszatekintés megtekintése",
|
||||
"LabelYourAudiobookDuration": "Hangoskönyv időtartama",
|
||||
"LabelYourBookmarks": "Könyvjelzőid",
|
||||
"LabelYourPlaylists": "Lejátszási listáid",
|
||||
@@ -619,10 +693,14 @@
|
||||
"MessageAddToPlayerQueue": "Hozzáadás a lejátszó sorhoz",
|
||||
"MessageAppriseDescription": "Ennek a funkció használatához futtatnia kell egy <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> példányt vagy egy olyan API-t, amely kezeli ezeket a kéréseket. <br />Az Apprise API URL-nek a teljes URL útvonalat kell tartalmaznia az értesítés elküldéséhez, például, ha az API példánya a <code>http://192.168.1.1:8337</code> címen szolgáltatva, akkor <code>http://192.168.1.1:8337/notify</code> értéket kell megadnia.",
|
||||
"MessageBackupsDescription": "A biztonsági másolatok tartalmazzák a felhasználókat, a felhasználói haladást, a könyvtári elem részleteit, a szerver beállításait és a képeket, amelyek a <code>/metadata/items</code> és <code>/metadata/authors</code> mappákban vannak tárolva. A biztonsági másolatok <strong>nem</strong> tartalmazzák a könyvtári mappákban tárolt fájlokat.",
|
||||
"MessageBackupsLocationEditNote": "Megjegyzés: A biztonsági mentés helyének frissítése nem mozgatja vagy módosítja a meglévő biztonsági mentéseket",
|
||||
"MessageBackupsLocationNoEditNote": "Megjegyzés: A biztonsági mentés helye egy környezeti változóval van beállítva, és itt nem módosítható.",
|
||||
"MessageBackupsLocationPathEmpty": "A biztonsági mentés helyének elérési útvonala nem lehet üres",
|
||||
"MessageBatchQuickMatchDescription": "A Gyors egyeztetés megpróbálja hozzáadni a hiányzó borítókat és metaadatokat a kiválasztott elemekhez. Engedélyezze az alábbi opciókat, hogy a Gyors egyeztetés felülírhassa a meglévő borítókat és/vagy metaadatokat.",
|
||||
"MessageBookshelfNoCollections": "Még nem készített gyűjteményeket",
|
||||
"MessageBookshelfNoRSSFeeds": "Nincsenek nyitott RSS hírcsatornák",
|
||||
"MessageBookshelfNoResultsForFilter": "Nincs eredmény a \"{0}: {1}\" szűrőre",
|
||||
"MessageBookshelfNoResultsForQuery": "Nincs eredmény a lekérdezéshez",
|
||||
"MessageBookshelfNoSeries": "Nincsenek sorozatai",
|
||||
"MessageChapterEndIsAfter": "A fejezet vége a hangoskönyv végét követi",
|
||||
"MessageChapterErrorFirstNotZero": "Az első fejezetnek 0:00-kor kell kezdődnie",
|
||||
@@ -632,17 +710,27 @@
|
||||
"MessageCheckingCron": "Cron ellenőrzése...",
|
||||
"MessageConfirmCloseFeed": "Biztosan be szeretné zárni ezt a hírcsatornát?",
|
||||
"MessageConfirmDeleteBackup": "Biztosan törölni szeretné a(z) {0} biztonsági másolatot?",
|
||||
"MessageConfirmDeleteDevice": "Biztos, hogy törölni szeretné a „{0}” e-olvasó eszközt?",
|
||||
"MessageConfirmDeleteFile": "Ez törölni fogja a fájlt a fájlrendszerből. Biztos benne?",
|
||||
"MessageConfirmDeleteLibrary": "Biztosan véglegesen törölni szeretné a(z) \"{0}\" könyvtárat?",
|
||||
"MessageConfirmDeleteLibraryItem": "Ez eltávolítja a könyvtári elemet az adatbázisból és a fájlrendszerből. Biztos benne?",
|
||||
"MessageConfirmDeleteLibraryItems": "Ez eltávolítja a(z) {0} könyvtári elemet az adatbázisból és a fájlrendszerből. Biztos benne?",
|
||||
"MessageConfirmDeleteMetadataProvider": "Biztos, hogy törölni szeretné a „{0}” egyéni metaadat-szolgáltatót?",
|
||||
"MessageConfirmDeleteNotification": "Biztos, hogy törölni szeretné ezt az értesítést?",
|
||||
"MessageConfirmDeleteSession": "Biztosan törölni szeretné ezt a munkamenetet?",
|
||||
"MessageConfirmEmbedMetadataInAudioFiles": "Biztos, hogy metaadatokat szeretne beágyazni {0} hangfájlba?",
|
||||
"MessageConfirmForceReScan": "Biztosan kényszeríteni szeretné az újraszkennelést?",
|
||||
"MessageConfirmMarkAllEpisodesFinished": "Biztosan meg szeretné jelölni az összes epizódot befejezettnek?",
|
||||
"MessageConfirmMarkAllEpisodesNotFinished": "Biztosan meg szeretné jelölni az összes epizódot nem befejezettnek?",
|
||||
"MessageConfirmMarkItemFinished": "Biztos, hogy a „{0}”-t befejezettnek akarja jelölni?",
|
||||
"MessageConfirmMarkItemNotFinished": "Biztos, hogy a „{0}”-t befejezetlennek akarja jelölni?",
|
||||
"MessageConfirmMarkSeriesFinished": "Biztosan meg szeretné jelölni a sorozat összes könyvét befejezettnek?",
|
||||
"MessageConfirmMarkSeriesNotFinished": "Biztosan meg szeretné jelölni a sorozat összes könyvét nem befejezettnek?",
|
||||
"MessageConfirmNotificationTestTrigger": "Ez az értesítés indítható tesztadatokkal?",
|
||||
"MessageConfirmPurgeCache": "A gyorsítótár kiürítése törli a teljes könyvtárat a <code>/metadata/cache</code> helyről. <br /><br />Biztosan eltávolítja a gyorsítótár könyvtárát?",
|
||||
"MessageConfirmPurgeItemsCache": "Az elemek gyorsítótárának kiürítése törli a teljes könyvtárat a <code>/metadata/cache/items</code> helyről.<br />Biztos benne?",
|
||||
"MessageConfirmQuickEmbed": "Figyelem! A Gyors beágyazás nem készít biztonsági másolatot az audiofájlokról. Győződjön meg arról, hogy van biztonsági másolata az audiofájlokról. <br><br>Szeretné folytatni?",
|
||||
"MessageConfirmQuickMatchEpisodes": "Az epizódok gyors megfeleltetése felülírja a részleteket, ha egyezést talál. Csak a nem egyező epizódok frissülnek. Biztos benne?",
|
||||
"MessageConfirmReScanLibraryItems": "Biztosan újra szeretné szkennelni a(z) {0} elemet?",
|
||||
"MessageConfirmRemoveAllChapters": "Biztosan eltávolítja az összes fejezetet?",
|
||||
"MessageConfirmRemoveAuthor": "Biztosan eltávolítja a(z) \"{0}\" szerzőt?",
|
||||
@@ -650,6 +738,7 @@
|
||||
"MessageConfirmRemoveEpisode": "Biztosan eltávolítja a(z) \"{0}\" epizódot?",
|
||||
"MessageConfirmRemoveEpisodes": "Biztosan eltávolítja a(z) {0} epizódot?",
|
||||
"MessageConfirmRemoveListeningSessions": "Biztosan eltávolítja a(z) {0} hallgatási munkamenetet?",
|
||||
"MessageConfirmRemoveMetadataFiles": "Biztos, hogy az összes metaadatot el akarja távolítani {0} fájl van könyvtár mappáiban?",
|
||||
"MessageConfirmRemoveNarrator": "Biztosan eltávolítja a(z) \"{0}\" előadót?",
|
||||
"MessageConfirmRemovePlaylist": "Biztosan eltávolítja a(z) \"{0}\" lejátszási listáját?",
|
||||
"MessageConfirmRenameGenre": "Biztosan át szeretné nevezni a(z) \"{0}\" műfajt \"{1}\"-re az összes elemnél?",
|
||||
@@ -658,11 +747,15 @@
|
||||
"MessageConfirmRenameTag": "Biztosan át szeretné nevezni a(z) \"{0}\" címkét \"{1}\"-re az összes elemnél?",
|
||||
"MessageConfirmRenameTagMergeNote": "Megjegyzés: Ez a címke már létezik, így össze lesznek vonva.",
|
||||
"MessageConfirmRenameTagWarning": "Figyelem! Egy hasonló, de eltérő nagybetűkkel rendelkező címke már létezik \"{0}\".",
|
||||
"MessageConfirmResetProgress": "Biztos, hogy vissza akarja állítani a haladási folyamatát?",
|
||||
"MessageConfirmSendEbookToDevice": "Biztosan el szeretné küldeni a(z) {0} e-könyvet a(z) \"{1}\" eszközre?",
|
||||
"MessageConfirmUnlinkOpenId": "Biztos, hogy el akarja távolítani ezt a felhasználót az OpenID-ból?",
|
||||
"MessageDownloadingEpisode": "Epizód letöltése",
|
||||
"MessageDragFilesIntoTrackOrder": "Húzza a fájlokat a helyes sávrendbe",
|
||||
"MessageEmbedFailed": "A beágyazás sikertelen!",
|
||||
"MessageEmbedFinished": "Beágyazás befejeződött!",
|
||||
"MessageEpisodesQueuedForDownload": "{0} epizód letöltésre vár",
|
||||
"MessageEreaderDevices": "Az e-könyvek kézbesítésének biztosítása érdekében a fenti e-mail címet az alább felsorolt minden egyes eszközhöz, mint érvényes feladót kell hozzáadnia.",
|
||||
"MessageFeedURLWillBe": "A hírcsatorna URL-je {0} lesz",
|
||||
"MessageFetching": "Lekérdezés...",
|
||||
"MessageForceReScanDescription": "minden fájlt újra szkennel, mint egy friss szkennelés. Az audiofájlok ID3 címkéi, OPF fájlok és szövegfájlok újként lesznek szkennelve.",
|
||||
@@ -670,10 +763,10 @@
|
||||
"MessageInsertChapterBelow": "Fejezet beszúrása alulra",
|
||||
"MessageItemsSelected": "{0} kiválasztott elem",
|
||||
"MessageItemsUpdated": "{0} frissített elem",
|
||||
"MessageJoinUsOn": "Csatlakozzon hozzánk",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} hallgatási munkamenet az elmúlt évben",
|
||||
"MessageJoinUsOn": "Csatlakozzon hozzánk a",
|
||||
"MessageLoading": "Betöltés...",
|
||||
"MessageLoadingFolders": "Mappák betöltése...",
|
||||
"MessageLogsDescription": "A naplók a <code>/metadata/logs</code> mappában JSON-fájlokként tárolódnak. Az összeomlási naplók a <code>/metadata/logs/crash_logs.txt</code> fájlban tárolódnak.",
|
||||
"MessageM4BFailed": "M4B sikertelen!",
|
||||
"MessageM4BFinished": "M4B befejeződött!",
|
||||
"MessageMapChapterTitles": "Fejezetcímek hozzárendelése a meglévő hangoskönyv fejezeteihez anélkül, hogy az időbélyegeket módosítaná",
|
||||
@@ -690,6 +783,7 @@
|
||||
"MessageNoCollections": "Nincsenek gyűjtemények",
|
||||
"MessageNoCoversFound": "Nem találhatóak borítók",
|
||||
"MessageNoDescription": "Nincs leírás",
|
||||
"MessageNoDevices": "Nincs eszköz",
|
||||
"MessageNoDownloadsInProgress": "Jelenleg nincsenek folyamatban lévő letöltések",
|
||||
"MessageNoDownloadsQueued": "Nincsenek várakozó letöltések",
|
||||
"MessageNoEpisodeMatchesFound": "Nincs találat az epizódokra",
|
||||
@@ -703,6 +797,7 @@
|
||||
"MessageNoLogs": "Nincsenek naplók",
|
||||
"MessageNoMediaProgress": "Nincs előrehaladás a médialejátszásban",
|
||||
"MessageNoNotifications": "Nincsenek értesítések",
|
||||
"MessageNoPodcastFeed": "Érvénytelen podcast: Nincs forrás",
|
||||
"MessageNoPodcastsFound": "Nem találhatóak podcastok",
|
||||
"MessageNoResults": "Nincsenek eredmények",
|
||||
"MessageNoSearchResultsFor": "Nincs keresési eredmény erre: \"{0}\"",
|
||||
@@ -712,11 +807,16 @@
|
||||
"MessageNoUpdatesWereNecessary": "Nem volt szükség frissítésekre",
|
||||
"MessageNoUserPlaylists": "Nincsenek felhasználói lejátszási listák",
|
||||
"MessageNotYetImplemented": "Még nem implementált",
|
||||
"MessageOpmlPreviewNote": "Megjegyzés: Ez egy előnézeti kép az elemzett OPML fájlról. A podcast tényleges címe az RSS hírcsatornából származik.",
|
||||
"MessageOr": "vagy",
|
||||
"MessagePauseChapter": "Fejezet lejátszásának szüneteltetése",
|
||||
"MessagePlayChapter": "Fejezet elejének meghallgatása",
|
||||
"MessagePlaylistCreateFromCollection": "Lejátszási lista létrehozása gyűjteményből",
|
||||
"MessagePleaseWait": "Kérem várjon...",
|
||||
"MessagePodcastHasNoRSSFeedForMatching": "A podcastnak nincs RSS hírcsatorna URL-je az egyeztetéshez",
|
||||
"MessagePodcastSearchField": "Adja meg a keresési kifejezést vagy az RSS hírcsatorna URL-címét",
|
||||
"MessageQuickEmbedInProgress": "Gyors beágyazás folyamatban",
|
||||
"MessageQuickMatchAllEpisodes": "Minden epizód gyors egyeztetése",
|
||||
"MessageQuickMatchDescription": "Üres elem részletek és borító feltöltése az első találati eredménnyel a(z) '{0}'-ból. Nem írja felül a részleteket, kivéve, ha a 'Preferált egyeztetett metaadatok' szerverbeállítás engedélyezve van.",
|
||||
"MessageRemoveChapter": "Fejezet eltávolítása",
|
||||
"MessageRemoveEpisodes": "Epizód(ok) eltávolítása: {0}",
|
||||
@@ -724,14 +824,49 @@
|
||||
"MessageRemoveUserWarning": "Biztosan véglegesen törölni szeretné a(z) \"{0}\" felhasználót?",
|
||||
"MessageReportBugsAndContribute": "Hibák jelentése, funkciók kérése és hozzájárulás itt",
|
||||
"MessageResetChaptersConfirm": "Biztosan alaphelyzetbe szeretné állítani a fejezeteket és visszavonni a módosításokat?",
|
||||
"MessageRestoreBackupConfirm": "Biztosan vissza szeretné állítani a biztonsági másolatot, amely ekkor készült",
|
||||
"MessageRestoreBackupConfirm": "Biztosan vissza szeretné állítani a biztonsági másolatot, amely ekkor készült:",
|
||||
"MessageRestoreBackupWarning": "A biztonsági mentés visszaállítása felülírja az egész adatbázist, amely a /config mappában található, valamint a borítóképeket a /metadata/items és /metadata/authors mappákban.<br /><br />A biztonsági mentések nem módosítják a könyvtár mappáiban található fájlokat. Ha engedélyezte a szerverbeállításokat a borítóképek és a metaadatok könyvtármappákban való tárolására, akkor ezek nem kerülnek biztonsági mentésre vagy felülírásra.<br /><br />A szerver használó összes kliens automatikusan frissül.",
|
||||
"MessageSearchResultsFor": "Keresési eredmények",
|
||||
"MessageSelected": "{0} kiválasztva",
|
||||
"MessageServerCouldNotBeReached": "A szervert nem lehet elérni",
|
||||
"MessageSetChaptersFromTracksDescription": "Fejezetek beállítása minden egyes hangfájlt egy fejezetként használva, és a fejezet címét a hangfájl neveként",
|
||||
"MessageShareExpirationWillBe": "A lejárat: <strong>{0}</strong>",
|
||||
"MessageShareExpiresIn": "{0} múlva jár le",
|
||||
"MessageStartPlaybackAtTime": "\"{0}\" lejátszásának kezdése {1} -tól?",
|
||||
"MessageThinking": "Gondolkodás...",
|
||||
"MessageTaskAudioFileNotWritable": "A/Az „{0}” hangfájl nem írható",
|
||||
"MessageTaskCanceledByUser": "Felhasználó törölte a feladatot",
|
||||
"MessageTaskDownloadingEpisodeDescription": "„{0}” epizód letöltése",
|
||||
"MessageTaskEmbeddingMetadata": "Metaadatok beágyazása",
|
||||
"MessageTaskEmbeddingMetadataDescription": "Metaadatok beágyazása a „{0}” hangoskönyvbe",
|
||||
"MessageTaskEncodingM4b": "Kódolás M4B-ban",
|
||||
"MessageTaskEncodingM4bDescription": "„{0}” hangoskönyv kódolása egyetlen m4b fájlba",
|
||||
"MessageTaskFailed": "Sikertelen",
|
||||
"MessageTaskFailedToBackupAudioFile": "Nem sikerült a „{0}” hangfájl mentése",
|
||||
"MessageTaskFailedToCreateCacheDirectory": "Nem sikerült létrehozni a gyorsítótár könyvtárat",
|
||||
"MessageTaskFailedToEmbedMetadataInFile": "Nem sikerült beágyazni a metaadatokat a „{0}” fájlba",
|
||||
"MessageTaskFailedToMergeAudioFiles": "A hangfájlok egyesítése nem sikerült",
|
||||
"MessageTaskFailedToMoveM4bFile": "Nem sikerült m4b fájlt áthelyezni",
|
||||
"MessageTaskFailedToWriteMetadataFile": "Metaadatfájl írása sikertelen",
|
||||
"MessageTaskMatchingBooksInLibrary": "Könyvek egyeztetése a \"{0}\" könyvtárban",
|
||||
"MessageTaskNoFilesToScan": "Nincs beolvasandó fájl",
|
||||
"MessageTaskOpmlImport": "OPML import",
|
||||
"MessageTaskOpmlImportDescription": "Podcastok létrehozása {0} RSS hírcsatornából",
|
||||
"MessageTaskOpmlImportFeedDescription": "RSS feed „{0}” importálása",
|
||||
"MessageTaskOpmlImportFeedFailed": "Nem sikerült letölteni a podcast feedet",
|
||||
"MessageTaskOpmlImportFeedPodcastDescription": "„{0}” podcast létrehozása",
|
||||
"MessageTaskOpmlImportFeedPodcastExists": "Podcast már létezik az elérési útvonalon",
|
||||
"MessageTaskOpmlImportFeedPodcastFailed": "Nem sikerült podcastot létrehozni",
|
||||
"MessageTaskOpmlImportFinished": "{0} podcast hozzáadva",
|
||||
"MessageTaskOpmlParseFailed": "Az OPML fájl elemzése nem sikerült",
|
||||
"MessageTaskOpmlParseFastFail": "Érvénytelen OPML fájl: <opml> tag nem található VAGY nem találtak <outline> taget",
|
||||
"MessageTaskScanItemsAdded": "{0} hozzáadva",
|
||||
"MessageTaskScanItemsMissing": "{0} hiányzik",
|
||||
"MessageTaskScanItemsUpdated": "{0} frissítve",
|
||||
"MessageTaskScanNoChangesNeeded": "Nincs szükség változtatásra",
|
||||
"MessageTaskScanningFileChanges": "Fájlváltozások keresése a „{0}” fájlban",
|
||||
"MessageTaskScanningLibrary": "„{0}” könyvtár beolvasása",
|
||||
"MessageTaskTargetDirectoryNotWritable": "A célkönyvtár nem írható",
|
||||
"MessageThinking": "Gondolkodom...",
|
||||
"MessageUploaderItemFailed": "A feltöltés sikertelen",
|
||||
"MessageUploaderItemSuccess": "Sikeresen feltöltve!",
|
||||
"MessageUploading": "Feltöltés...",
|
||||
@@ -743,45 +878,100 @@
|
||||
"NoteChangeRootPassword": "A Root felhasználó az egyetlen felhasználó, akinek lehet üres jelszava",
|
||||
"NoteChapterEditorTimes": "Megjegyzés: Az első fejezet kezdőidejének 0:00 kell lennie, és az utolsó fejezet kezdőideje nem haladhatja meg a hangoskönyv időtartamát.",
|
||||
"NoteFolderPicker": "Megjegyzés: azok a mappák, amelyek már hozzá vannak rendelve, nem jelennek meg",
|
||||
"NoteRSSFeedPodcastAppsHttps": "Figyelem: A legtöbb podcast alkalmazás megköveteli, hogy az RSS feed URL HTTPS-t használjon",
|
||||
"NoteRSSFeedPodcastAppsHttps": "Figyelem: A legtöbb podcast alkalmazás megköveteli, hogy az RSS hírcsatorna URL-jában HTTPS-t használjon",
|
||||
"NoteRSSFeedPodcastAppsPubDate": "Figyelem: Az egy vagy több epizódnak nincs Közzétételi dátuma. Néhány podcast alkalmazás ezt megköveteli.",
|
||||
"NoteUploaderFoldersWithMediaFiles": "A médiafájlokat tartalmazó mappák külön könyvtári tételekként lesznek kezelve.",
|
||||
"NoteUploaderOnlyAudioFiles": "Ha csak hangfájlokat tölt fel, akkor minden egyes hangfájl külön hangoskönyvként lesz kezelve.",
|
||||
"NoteUploaderUnsupportedFiles": "A nem támogatott fájlok figyelmen kívül hagyásra kerülnek. Mappa kiválasztása vagy elengedésekor az elem mappáján kívüli egyéb fájlok figyelmen kívül lesznek hagyva.",
|
||||
"NotificationOnBackupCompletedDescription": "A biztonsági mentés befejezésekor aktiválódik",
|
||||
"NotificationOnBackupFailedDescription": "A biztonsági mentés sikertelensége esetén aktiválódik",
|
||||
"NotificationOnEpisodeDownloadedDescription": "Egy podcast epizód automatikus letöltésekor aktiválódik",
|
||||
"NotificationOnTestDescription": "Esemény az értesítési rendszer teszteléséhez",
|
||||
"PlaceholderNewCollection": "Új gyűjtemény neve",
|
||||
"PlaceholderNewFolderPath": "Új mappa útvonala",
|
||||
"PlaceholderNewPlaylist": "Új lejátszási lista neve",
|
||||
"PlaceholderSearch": "Keresés..",
|
||||
"PlaceholderSearchEpisode": "Epizód keresése..",
|
||||
"StatsAuthorsAdded": "szerző hozzáadva",
|
||||
"StatsBooksAdded": "könyv hozzáadva",
|
||||
"StatsBooksAdditional": "Néhány kiegészítés…",
|
||||
"StatsBooksFinished": "könyv befejezve",
|
||||
"StatsBooksFinishedThisYear": "Néhány idén befejezett könyv…",
|
||||
"StatsBooksListenedTo": "hallgatott könyv",
|
||||
"StatsCollectionGrewTo": "Könyvgyűjtemény nőtt…",
|
||||
"StatsSessions": "munkamenet",
|
||||
"StatsSpentListening": "hallgatással töltött idő",
|
||||
"StatsTopAuthor": "TOP SZERZŐ",
|
||||
"StatsTopAuthors": "TOP SZERZŐ",
|
||||
"StatsTopGenre": "TOP MŰFAJ",
|
||||
"StatsTopGenres": "TOP MŰFAJ",
|
||||
"StatsTopMonth": "TOP HÓNAP",
|
||||
"StatsTopNarrator": "TOP ELŐADÓ",
|
||||
"StatsTopNarrators": "TOP ELŐADÓ",
|
||||
"StatsTotalDuration": "A teljes időtartam…",
|
||||
"StatsYearInReview": "ÉVVISSZATEKINTÉS",
|
||||
"ToastAccountUpdateSuccess": "Fiók frissítve",
|
||||
"ToastAppriseUrlRequired": "Meg kell adnia egy Apprise URL-címet",
|
||||
"ToastAsinRequired": "ASIN kötelező",
|
||||
"ToastAuthorImageRemoveSuccess": "Szerző képe eltávolítva",
|
||||
"ToastAuthorNotFound": "A szerző „{0}” nem található",
|
||||
"ToastAuthorRemoveSuccess": "Szerző eltávolítva",
|
||||
"ToastAuthorSearchNotFound": "Szerző nem található",
|
||||
"ToastAuthorUpdateMerged": "Szerző összevonva",
|
||||
"ToastAuthorUpdateSuccess": "Szerző frissítve",
|
||||
"ToastAuthorUpdateSuccessNoImageFound": "Szerző frissítve (nem található kép)",
|
||||
"ToastBackupAppliedSuccess": "Biztonsági mentés alkalmazva",
|
||||
"ToastBackupCreateFailed": "A biztonsági mentés létrehozása sikertelen",
|
||||
"ToastBackupCreateSuccess": "Biztonsági mentés létrehozva",
|
||||
"ToastBackupDeleteFailed": "A biztonsági mentés törlése sikertelen",
|
||||
"ToastBackupDeleteSuccess": "Biztonsági mentés törölve",
|
||||
"ToastBackupInvalidMaxKeep": "A megőrzendő biztonsági másolatok száma érvénytelen",
|
||||
"ToastBackupInvalidMaxSize": "Érvénytelen maximális mentésméret",
|
||||
"ToastBackupRestoreFailed": "A biztonsági mentés visszaállítása sikertelen",
|
||||
"ToastBackupUploadFailed": "A biztonsági mentés feltöltése sikertelen",
|
||||
"ToastBackupUploadSuccess": "Biztonsági mentés feltöltve",
|
||||
"ToastBatchDeleteFailed": "A tömeges törlés nem sikerült",
|
||||
"ToastBatchDeleteSuccess": "Sikeres tömeges törlés",
|
||||
"ToastBatchUpdateFailed": "Kötegelt frissítés sikertelen",
|
||||
"ToastBatchUpdateSuccess": "Kötegelt frissítés sikeres",
|
||||
"ToastBookmarkCreateFailed": "Könyvjelző létrehozása sikertelen",
|
||||
"ToastBookmarkCreateSuccess": "Könyvjelző hozzáadva",
|
||||
"ToastBookmarkRemoveSuccess": "Könyvjelző eltávolítva",
|
||||
"ToastBookmarkUpdateSuccess": "Könyvjelző frissítve",
|
||||
"ToastCachePurgeFailed": "A gyorsítótár törlése sikertelen",
|
||||
"ToastCachePurgeSuccess": "A gyorsítótár sikeresen törölve",
|
||||
"ToastChaptersHaveErrors": "A fejezetek hibákat tartalmaznak",
|
||||
"ToastChaptersMustHaveTitles": "A fejezeteknek címekkel kell rendelkezniük",
|
||||
"ToastCollectionItemsRemoveSuccess": "Elem(ek) eltávolítva a gyűjteményből",
|
||||
"ToastChaptersRemoved": "Fejezetek eltávolítva",
|
||||
"ToastChaptersUpdated": "Fejezetek frissítve",
|
||||
"ToastCollectionRemoveSuccess": "Gyűjtemény eltávolítva",
|
||||
"ToastCollectionUpdateSuccess": "Gyűjtemény frissítve",
|
||||
"ToastCoverUpdateFailed": "A borító frissítése nem sikerült",
|
||||
"ToastDeleteFileFailed": "Nem sikerült törölni a fájlt",
|
||||
"ToastDeleteFileSuccess": "Fájl törölve",
|
||||
"ToastDeviceAddFailed": "Nem sikerült eszközt hozzáadni",
|
||||
"ToastDeviceNameAlreadyExists": "Ilyen nevű olvasóeszköz már létezik",
|
||||
"ToastDeviceTestEmailFailed": "Teszt email küldése sikertelen",
|
||||
"ToastDeviceTestEmailSuccess": "Teszt email elküldve",
|
||||
"ToastEmailSettingsUpdateSuccess": "Email beállítások frissítve",
|
||||
"ToastEncodeCancelSucces": "Kódolás törölve",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "Nem sikerült törölni a várólistát",
|
||||
"ToastEpisodeUpdateSuccess": "{0} epizód frissítve",
|
||||
"ToastFailedToLoadData": "Sikertelen adatbetöltés",
|
||||
"ToastFailedToMatch": "Nem sikerült egyezőséget találni",
|
||||
"ToastFailedToShare": "Nem sikerült megosztani",
|
||||
"ToastFailedToUpdate": "Nem sikerült frissíteni",
|
||||
"ToastInvalidImageUrl": "Érvénytelen a kép URL címe",
|
||||
"ToastInvalidUrl": "Érvénytelen URL",
|
||||
"ToastItemCoverUpdateSuccess": "Elem borítója frissítve",
|
||||
"ToastItemDeletedFailed": "Nem sikerült törölni az elemet",
|
||||
"ToastItemDeletedSuccess": "Elem törölve",
|
||||
"ToastItemDetailsUpdateSuccess": "Elem részletei frissítve",
|
||||
"ToastItemMarkedAsFinishedFailed": "Megjelölés Befejezettként sikertelen",
|
||||
"ToastItemMarkedAsFinishedSuccess": "Elem megjelölve Befejezettként",
|
||||
"ToastItemMarkedAsNotFinishedFailed": "Az elem befejezetlennek jelölése sikertelen",
|
||||
"ToastItemMarkedAsNotFinishedSuccess": "Elem megjelölve Nem Befejezettként",
|
||||
"ToastItemUpdateSuccess": "Elem frissítve",
|
||||
"ToastLibraryCreateFailed": "Könyvtár létrehozása sikertelen",
|
||||
"ToastLibraryCreateSuccess": "\"{0}\" könyvtár létrehozva",
|
||||
"ToastLibraryDeleteFailed": "Könyvtár törlése sikertelen",
|
||||
@@ -789,14 +979,34 @@
|
||||
"ToastLibraryScanFailedToStart": "A beolvasás elindítása sikertelen",
|
||||
"ToastLibraryScanStarted": "Könyvtár beolvasása elindítva",
|
||||
"ToastLibraryUpdateSuccess": "\"{0}\" könyvtár frissítve",
|
||||
"ToastMatchAllAuthorsFailed": "Nem sikerült az összes szerzőt azonosítani",
|
||||
"ToastMetadataFilesRemovedError": "Hiba a metaadatok eltávolításakor.{0} fájl",
|
||||
"ToastMetadataFilesRemovedNoneFound": "Nincsenek metaadatok.{0} fájl a könyvtárban",
|
||||
"ToastMetadataFilesRemovedNoneRemoved": "Nincsenek metaadatok.{0} fájl eltávolítva",
|
||||
"ToastMetadataFilesRemovedSuccess": "{0} metaadat.{1} fájl eltávolítva",
|
||||
"ToastMustHaveAtLeastOnePath": "Legalább egy elérési útvonalnak kell lennie",
|
||||
"ToastNameEmailRequired": "Név és e-mail cím megadása kötelező",
|
||||
"ToastNameRequired": "A név megadása kötelező",
|
||||
"ToastNewEpisodesFound": "{0} új epizód",
|
||||
"ToastNewUserCreatedFailed": "Nem sikerült a fiókot létrehozni: „{0}”",
|
||||
"ToastNewUserCreatedSuccess": "Új fiók létrehozva",
|
||||
"ToastNewUserLibraryError": "Legalább egy könyvtárat ki kell választani",
|
||||
"ToastNewUserPasswordError": "Kötelező a jelszó, csak a root felhasználónak lehet üres jelszava",
|
||||
"ToastNewUserUsernameError": "Adjon meg egy felhasználónevet",
|
||||
"ToastNoNewEpisodesFound": "Nincs új epizód",
|
||||
"ToastNoUpdatesNecessary": "Nincs szükség frissítésre",
|
||||
"ToastNotificationSettingsUpdateSuccess": "Értesítési beállítások frissítve",
|
||||
"ToastNotificationUpdateSuccess": "Értesítés frissítve",
|
||||
"ToastPlaylistCreateFailed": "Lejátszási lista létrehozása sikertelen",
|
||||
"ToastPlaylistCreateSuccess": "Lejátszási lista létrehozva",
|
||||
"ToastPlaylistRemoveSuccess": "Lejátszási lista eltávolítva",
|
||||
"ToastPlaylistUpdateSuccess": "Lejátszási lista frissítve",
|
||||
"ToastPodcastCreateFailed": "Podcast létrehozása sikertelen",
|
||||
"ToastPodcastCreateSuccess": "A podcast sikeresen létrehozva",
|
||||
"ToastPodcastNoEpisodesInFeed": "Nincsenek epizódok az RSS hírcsatornában",
|
||||
"ToastPodcastNoRssFeed": "A podcastnak nincs RSS-hírcsatornája",
|
||||
"ToastRSSFeedCloseFailed": "Az RSS hírcsatorna bezárása sikertelen",
|
||||
"ToastRSSFeedCloseSuccess": "RSS feed bezárva",
|
||||
"ToastRSSFeedCloseSuccess": "RSS hírfolyam leállítva",
|
||||
"ToastRemoveItemFromCollectionFailed": "Tétel eltávolítása a gyűjteményből sikertelen",
|
||||
"ToastRemoveItemFromCollectionSuccess": "Tétel eltávolítva a gyűjteményből",
|
||||
"ToastSendEbookToDeviceFailed": "E-könyv küldése az eszközre sikertelen",
|
||||
@@ -808,6 +1018,9 @@
|
||||
"ToastSocketConnected": "Socket csatlakoztatva",
|
||||
"ToastSocketDisconnected": "Socket lecsatlakoztatva",
|
||||
"ToastSocketFailedToConnect": "A Socket csatlakoztatása sikertelen",
|
||||
"ToastUnknownError": "Ismeretlen hiba",
|
||||
"ToastUserDeleteFailed": "Felhasználó törlése sikertelen",
|
||||
"ToastUserDeleteSuccess": "Felhasználó törölve"
|
||||
"ToastUserDeleteSuccess": "Felhasználó törölve",
|
||||
"ToastUserPasswordChangeSuccess": "Jelszó sikeresen megváltoztatva",
|
||||
"ToastUserRootRequireName": "Egy root felhasználónevet kell megadnia"
|
||||
}
|
||||
|
||||
+55
-10
@@ -66,13 +66,13 @@
|
||||
"ButtonPurgeItemsCache": "Elimina la Cache selezionata",
|
||||
"ButtonQueueAddItem": "Aggiungi alla Coda",
|
||||
"ButtonQueueRemoveItem": "Rimuovi dalla Coda",
|
||||
"ButtonQuickEmbed": "Quick Embed",
|
||||
"ButtonQuickEmbed": "Incorporazione Rapida",
|
||||
"ButtonQuickEmbedMetadata": "Incorporamento rapido Metadati",
|
||||
"ButtonQuickMatch": "Controlla Metadata Auto",
|
||||
"ButtonReScan": "Ri-scansiona",
|
||||
"ButtonRead": "Leggi",
|
||||
"ButtonReadLess": "Leggi di Meno",
|
||||
"ButtonReadMore": "Leggi di Più",
|
||||
"ButtonReadLess": "Riduci",
|
||||
"ButtonReadMore": "Espandi",
|
||||
"ButtonRefresh": "Aggiorna",
|
||||
"ButtonRemove": "Rimuovi",
|
||||
"ButtonRemoveAll": "Rimuovi Tutto",
|
||||
@@ -163,6 +163,7 @@
|
||||
"HeaderNotificationUpdate": "Aggiornamento della notifica",
|
||||
"HeaderNotifications": "Notifiche",
|
||||
"HeaderOpenIDConnectAuthentication": "Autenticazione OpenID Connect",
|
||||
"HeaderOpenListeningSessions": "Apri sessioni di ascolto",
|
||||
"HeaderOpenRSSFeed": "Apri il flusso RSS",
|
||||
"HeaderOtherFiles": "Altri File",
|
||||
"HeaderPasswordAuthentication": "Autenticazione della password",
|
||||
@@ -180,6 +181,7 @@
|
||||
"HeaderRemoveEpisodes": "Rimuovi {0} Episodi",
|
||||
"HeaderSavedMediaProgress": "Progressi salvati",
|
||||
"HeaderSchedule": "Schedula",
|
||||
"HeaderScheduleEpisodeDownloads": "Imposta il download automatico degli episodi",
|
||||
"HeaderScheduleLibraryScans": "Schedula la scansione della libreria",
|
||||
"HeaderSession": "Sessione",
|
||||
"HeaderSetBackupSchedule": "Imposta programmazione Backup",
|
||||
@@ -218,13 +220,14 @@
|
||||
"LabelAddToPlaylist": "Aggiungi alla playlist",
|
||||
"LabelAddToPlaylistBatch": "Aggiungi {0} file alla Playlist",
|
||||
"LabelAddedAt": "Aggiunto il",
|
||||
"LabelAddedDate": "{0} aggiunti",
|
||||
"LabelAddedDate": "Aggiunti {0}",
|
||||
"LabelAdminUsersOnly": "Solo utenti Amministratori",
|
||||
"LabelAll": "Tutti",
|
||||
"LabelAllUsers": "Tutti gli Utenti",
|
||||
"LabelAllUsersExcludingGuests": "Tutti gli Utenti Esclusi gli ospiti",
|
||||
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
|
||||
"LabelAlreadyInYourLibrary": "Già esistente nella libreria",
|
||||
"LabelApiToken": "API Token",
|
||||
"LabelAppend": "Appese",
|
||||
"LabelAudioBitrate": "Audio Bitrate (es. 128k)",
|
||||
"LabelAudioChannels": "Canali Audio (1 o 2)",
|
||||
@@ -250,15 +253,18 @@
|
||||
"LabelBackupsNumberToKeep": "Numero di backup da mantenere",
|
||||
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
|
||||
"LabelBitrate": "Velocità di trasmissione",
|
||||
"LabelBonus": "Bonus",
|
||||
"LabelBooks": "Libri",
|
||||
"LabelButtonText": "Buttone Testo",
|
||||
"LabelByAuthor": "da {0}",
|
||||
"LabelChangePassword": "Cambia Password",
|
||||
"LabelChannels": "Canali",
|
||||
"LabelChapterCount": "{0} Capitoli",
|
||||
"LabelChapterTitle": "Titoli dei Capitoli",
|
||||
"LabelChapters": "Capitoli",
|
||||
"LabelChaptersFound": "Capitoli Trovati",
|
||||
"LabelClickForMoreInfo": "Click per altre Info",
|
||||
"LabelClickToUseCurrentValue": "Clicca per usare il valore corrente",
|
||||
"LabelClosePlayer": "Chiudi player",
|
||||
"LabelCodec": "Codec",
|
||||
"LabelCollapseSeries": "Comprimi Serie",
|
||||
@@ -320,9 +326,13 @@
|
||||
"LabelEnd": "Fine",
|
||||
"LabelEndOfChapter": "Fine Capitolo",
|
||||
"LabelEpisode": "Episodio",
|
||||
"LabelEpisodeNotLinkedToRssFeed": "Episode non linkati nel RSS feed",
|
||||
"LabelEpisodeNumber": "Episodio #{0}",
|
||||
"LabelEpisodeTitle": "Titolo Episodio",
|
||||
"LabelEpisodeType": "Tipo Episodio",
|
||||
"LabelEpisodeUrlFromRssFeed": "URL dell'episodio dal RSS feed",
|
||||
"LabelEpisodes": "Episodi",
|
||||
"LabelEpisodic": "Episodico",
|
||||
"LabelExample": "Esempio",
|
||||
"LabelExpandSeries": "Espandi Serie",
|
||||
"LabelExpandSubSeries": "Espandi Sub Serie",
|
||||
@@ -350,6 +360,7 @@
|
||||
"LabelFontScale": "Dimensione font",
|
||||
"LabelFontStrikethrough": "Barrato",
|
||||
"LabelFormat": "Formato",
|
||||
"LabelFull": "Pieno",
|
||||
"LabelGenre": "Genere",
|
||||
"LabelGenres": "Generi",
|
||||
"LabelHardDeleteFile": "Elimina Definitivamente",
|
||||
@@ -405,6 +416,10 @@
|
||||
"LabelLowestPriority": "Priorità Minima",
|
||||
"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",
|
||||
"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",
|
||||
"LabelMediaType": "Tipo Media",
|
||||
"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.",
|
||||
"LabelOpenRSSFeed": "Apri RSS Feed",
|
||||
"LabelOverwrite": "Sovrascrivi",
|
||||
"LabelPaginationPageXOfY": "Pagina {0} di {1}",
|
||||
"LabelPassword": "Password",
|
||||
"LabelPath": "Percorso",
|
||||
"LabelPermanent": "Permanente",
|
||||
"LabelPermissionsAccessAllLibraries": "Può accedere a tutte le librerie",
|
||||
"LabelPermissionsAccessAllTags": "Può accedere a tutti i tag",
|
||||
"LabelPermissionsAccessExplicitContent": "Può accedere a contenuti espliciti",
|
||||
"LabelPermissionsCreateEreader": "Può creare un e-reader",
|
||||
"LabelPermissionsDelete": "Può Cancellare",
|
||||
"LabelPermissionsDownload": "Può Scaricare",
|
||||
"LabelPermissionsUpdate": "Può Aggiornare",
|
||||
@@ -478,7 +495,7 @@
|
||||
"LabelProviderAuthorizationValue": "Authorization Header Value",
|
||||
"LabelPubDate": "Data di pubblicazione",
|
||||
"LabelPublishYear": "Anno di pubblicazione",
|
||||
"LabelPublishedDate": "{0} pubblicati",
|
||||
"LabelPublishedDate": "Pubblicati {0}",
|
||||
"LabelPublishedDecade": "Decennio di pubblicazione",
|
||||
"LabelPublishedDecades": "Decenni di pubblicazione",
|
||||
"LabelPublisher": "Editore",
|
||||
@@ -500,18 +517,24 @@
|
||||
"LabelRedo": "Rifai",
|
||||
"LabelRegion": "Regione",
|
||||
"LabelReleaseDate": "Data Release",
|
||||
"LabelRemoveAllMetadataAbs": "Remuovi tutti i metadata.abs files",
|
||||
"LabelRemoveAllMetadataJson": "Rimuovi tutti i metadata.json files",
|
||||
"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",
|
||||
"LabelSearchTerm": "Ricerca",
|
||||
"LabelSearchTitle": "Cerca Titolo",
|
||||
"LabelSearchTitleOrASIN": "Cerca titolo o ASIN",
|
||||
"LabelSeason": "Stagione",
|
||||
"LabelSeasonNumber": "Stagione #{0}",
|
||||
"LabelSelectAll": "Seleziona tutto",
|
||||
"LabelSelectAllEpisodes": "Seleziona tutti gli Episodi",
|
||||
"LabelSelectEpisodesShowing": "Selezionati {0} episodi da visualizzare",
|
||||
"LabelSelectUsers": "Selezione Utenti",
|
||||
"LabelSendEbookToDevice": "Invia il libro a...",
|
||||
"LabelSequence": "Sequenza",
|
||||
"LabelSerial": "Seriale",
|
||||
"LabelSeries": "Serie",
|
||||
"LabelSeriesName": "Nome Serie",
|
||||
"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.",
|
||||
"LabelSettingsHomePageBookshelfView": "Home page 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",
|
||||
"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",
|
||||
@@ -604,6 +630,7 @@
|
||||
"LabelTimeDurationXMinutes": "{0} minuti",
|
||||
"LabelTimeDurationXSeconds": "{0} secondi",
|
||||
"LabelTimeInMinutes": "Tempo in minuti",
|
||||
"LabelTimeLeft": "{0} sinistra",
|
||||
"LabelTimeListened": "Tempo di Ascolto",
|
||||
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
||||
"LabelTimeRemaining": "{0} rimanente",
|
||||
@@ -624,6 +651,7 @@
|
||||
"LabelTracksMultiTrack": "Multi-traccia",
|
||||
"LabelTracksNone": "Nessuna traccia",
|
||||
"LabelTracksSingleTrack": "Traccia-singola",
|
||||
"LabelTrailer": "Trailer",
|
||||
"LabelType": "Tipo",
|
||||
"LabelUnabridged": "Integrale",
|
||||
"LabelUndo": "Annulla",
|
||||
@@ -640,6 +668,7 @@
|
||||
"LabelUseAdvancedOptions": "Usa le opzioni avanzate",
|
||||
"LabelUseChapterTrack": "Usa il Capitolo della Traccia",
|
||||
"LabelUseFullTrack": "Usa la traccia totale",
|
||||
"LabelUseZeroForUnlimited": "Usa 0 per illimitato",
|
||||
"LabelUser": "Utente",
|
||||
"LabelUsername": "Nome utente",
|
||||
"LabelValue": "Valore",
|
||||
@@ -653,7 +682,7 @@
|
||||
"LabelXBooks": "{0} libri",
|
||||
"LabelXItems": "{0} oggetti",
|
||||
"LabelYearReviewHide": "Nascondi Anno in rassegna",
|
||||
"LabelYearReviewShow": "Vedi Anno in rassegna",
|
||||
"LabelYearReviewShow": "Mostra Anno in rassegna",
|
||||
"LabelYourAudiobookDuration": "La durata dell'audiolibro",
|
||||
"LabelYourBookmarks": "I tuoi preferiti",
|
||||
"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?",
|
||||
"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?",
|
||||
"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?",
|
||||
"MessageConfirmRemoveAllChapters": "Sei sicuro di voler rimuovere tutti i capitoli?",
|
||||
"MessageConfirmRemoveAuthor": "Sei sicuro di voler rimuovere l'autore? \"{0}\"?",
|
||||
@@ -705,6 +735,7 @@
|
||||
"MessageConfirmRemoveEpisode": "Sei sicuro di voler rimuovere l'episodio \"{0}\"?",
|
||||
"MessageConfirmRemoveEpisodes": "Sei sicuro di voler rimuovere {0} episodi?",
|
||||
"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}\"?",
|
||||
"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?",
|
||||
@@ -731,7 +762,6 @@
|
||||
"MessageItemsSelected": "{0} oggetti Selezionati",
|
||||
"MessageItemsUpdated": "{0} Oggetti aggiornati",
|
||||
"MessageJoinUsOn": "Unisciti a noi su",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} sessioni di ascolto nell'ultimo anno",
|
||||
"MessageLoading": "Caricamento…",
|
||||
"MessageLoadingFolders": "Caricamento Cartelle...",
|
||||
"MessageLogsDescription": "I log vengono archiviati nel percorso <code>/metadata/logs</code> as JSON files. I registri degli arresti anomali vengono archiviati nel percorso <code>/metadata/logs/crash_logs.txt</code>.",
|
||||
@@ -748,7 +778,7 @@
|
||||
"MessageNoBackups": "Nessun Backup",
|
||||
"MessageNoBookmarks": "Nessun preferito",
|
||||
"MessageNoChapters": "Nessun capitolo",
|
||||
"MessageNoCollections": "Nessuna Raccolta",
|
||||
"MessageNoCollections": "Nessuna Collezione",
|
||||
"MessageNoCoversFound": "Nessuna Cover Trovata",
|
||||
"MessageNoDescription": "Nessuna descrizione",
|
||||
"MessageNoDevices": "nessun dispositivo",
|
||||
@@ -785,6 +815,7 @@
|
||||
"MessagePodcastSearchField": "Inserisci il termine di ricerca o l'URL del feed RSS",
|
||||
"MessageQuickEmbedInProgress": "Incorporamento rapido in corso",
|
||||
"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\".",
|
||||
"MessageRemoveChapter": "Rimuovi Capitolo",
|
||||
"MessageRemoveEpisodes": "rimuovi {0} episodio(i)",
|
||||
@@ -883,6 +914,7 @@
|
||||
"StatsYearInReview": "ANNO IN RASSEGNA",
|
||||
"ToastAccountUpdateSuccess": "Account Aggiornato",
|
||||
"ToastAppriseUrlRequired": "È necessario immettere un indirizzo Apprise",
|
||||
"ToastAsinRequired": "L'ASIN è obbligatorio",
|
||||
"ToastAuthorImageRemoveSuccess": "Immagine Autore Rimossa",
|
||||
"ToastAuthorNotFound": "Autore\"{0}\" non trovato",
|
||||
"ToastAuthorRemoveSuccess": "Autore rimosso",
|
||||
@@ -902,6 +934,8 @@
|
||||
"ToastBackupUploadSuccess": "Backup caricato",
|
||||
"ToastBatchDeleteFailed": "Eliminazione batch non 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",
|
||||
"ToastBatchUpdateSuccess": "Batch di aggiornamento finito",
|
||||
"ToastBookmarkCreateFailed": "Creazione segnalibro fallita",
|
||||
@@ -913,9 +947,8 @@
|
||||
"ToastChaptersHaveErrors": "I capitoli contengono errori",
|
||||
"ToastChaptersMustHaveTitles": "I capitoli devono avere titoli",
|
||||
"ToastChaptersRemoved": "Capitoli rimossi",
|
||||
"ToastChaptersUpdated": "Capitoli aggiornati",
|
||||
"ToastCollectionItemsAddFailed": "l'aggiunta dell'elemento(i) alla raccolta non è riuscito",
|
||||
"ToastCollectionItemsAddSuccess": "L'aggiunta dell'elemento(i) alla raccolta è riuscito",
|
||||
"ToastCollectionItemsRemoveSuccess": "Oggetto(i) rimossi dalla Raccolta",
|
||||
"ToastCollectionRemoveSuccess": "Collezione rimossa",
|
||||
"ToastCollectionUpdateSuccess": "Raccolta aggiornata",
|
||||
"ToastCoverUpdateFailed": "Aggiornamento cover fallito",
|
||||
@@ -930,11 +963,14 @@
|
||||
"ToastEncodeCancelSucces": "Codifica annullata",
|
||||
"ToastEpisodeDownloadQueueClearFailed": "Impossibile cancellare la coda",
|
||||
"ToastEpisodeDownloadQueueClearSuccess": "Coda di download degli episodi cancellata",
|
||||
"ToastEpisodeUpdateSuccess": "{0} episodi aggiornati",
|
||||
"ToastErrorCannotShare": "Impossibile condividere in modo nativo su questo dispositivo",
|
||||
"ToastFailedToLoadData": "Impossibile caricare i dati",
|
||||
"ToastFailedToMatch": "Impossibile abbinare",
|
||||
"ToastFailedToShare": "Impossibile condividere",
|
||||
"ToastFailedToUpdate": "Non aggiornato",
|
||||
"ToastInvalidImageUrl": "URL dell'immagine non valido",
|
||||
"ToastInvalidMaxEpisodesToDownload": "Numero massimo di episodi non valido da scaricare",
|
||||
"ToastInvalidUrl": "URL non valido",
|
||||
"ToastItemCoverUpdateSuccess": "Cover aggiornata",
|
||||
"ToastItemDeletedFailed": "Impossibile eliminare l'elemento",
|
||||
@@ -953,14 +989,21 @@
|
||||
"ToastLibraryScanStarted": "Scansione Libreria iniziata",
|
||||
"ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata",
|
||||
"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",
|
||||
"ToastNameRequired": "Il nome è obbligatorio",
|
||||
"ToastNewEpisodesFound": "{0} nuovi episodi trovati",
|
||||
"ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"",
|
||||
"ToastNewUserCreatedSuccess": "Nuovo account creato",
|
||||
"ToastNewUserLibraryError": "È necessario selezionare almeno una libreria",
|
||||
"ToastNewUserPasswordError": "Deve avere una password, solo l'utente root può avere una password vuota",
|
||||
"ToastNewUserTagError": "Devi selezionare almeno un tag",
|
||||
"ToastNewUserUsernameError": "Inserisci un nome utente",
|
||||
"ToastNoNewEpisodesFound": "Nessun nuovo episodio trovato",
|
||||
"ToastNoUpdatesNecessary": "Nessun aggiornamento necessario",
|
||||
"ToastNotificationCreateFailed": "Impossibile creare la notifica",
|
||||
"ToastNotificationDeleteFailed": "Impossibile eliminare la notifica",
|
||||
@@ -979,6 +1022,7 @@
|
||||
"ToastPodcastGetFeedFailed": "Impossibile ottenere il feed del podcast",
|
||||
"ToastPodcastNoEpisodesInFeed": "Nessun episodio trovato nel feed RSS",
|
||||
"ToastPodcastNoRssFeed": "Il podcast non ha un feed RSS",
|
||||
"ToastProgressIsNotBeingSynced": "L'avanzamento non è sincronizzato, riavviare la riproduzione",
|
||||
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
|
||||
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
|
||||
"ToastProviderNameAndUrlRequired": "Nome e URL richiesti",
|
||||
@@ -1005,6 +1049,7 @@
|
||||
"ToastSessionCloseFailed": "Disconnessione Fallita",
|
||||
"ToastSessionDeleteFailed": "Errore eliminazione sessione",
|
||||
"ToastSessionDeleteSuccess": "Sessione cancellata",
|
||||
"ToastSleepTimerDone": "Timer di spegnimento eseguito... zZzzZz",
|
||||
"ToastSlugMustChange": "Lo slug contiene caratteri non validi",
|
||||
"ToastSlugRequired": "È richiesto lo slug",
|
||||
"ToastSocketConnected": "Socket connesso",
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
"ButtonViewAll": "Peržiūrėti visus",
|
||||
"ButtonYes": "Taip",
|
||||
"ErrorUploadFetchMetadataAPI": "Klaida gaunant metaduomenis",
|
||||
"ErrorUploadFetchMetadataNoResults": "Nepavyko gauti metaduomenų - pabandykite atnaujinti pavadinimą ir/ar autorių.",
|
||||
"ErrorUploadFetchMetadataNoResults": "Nepavyko gauti metaduomenų - pabandykite atnaujinti pavadinimą ir/ar autorių",
|
||||
"ErrorUploadLacksTitle": "Pavadinimas yra privalomas",
|
||||
"HeaderAccount": "Paskyra",
|
||||
"HeaderAdvanced": "Papildomi",
|
||||
@@ -419,7 +419,7 @@
|
||||
"LabelSettingsExperimentalFeatures": "Eksperimentiniai funkcionalumai",
|
||||
"LabelSettingsExperimentalFeaturesHelp": "Funkcijos, kurios yra kuriamos ir laukiami jūsų komentarai. Spustelėkite, kad atidarytumėte „GitHub“ diskusiją.",
|
||||
"LabelSettingsFindCovers": "Rasti viršelius",
|
||||
"LabelSettingsFindCoversHelp": "Jei jūsų audioknyga neturi įterpto viršelio arba viršelio paveikslėlio aplanke, bandyti rasti viršelį.<br>Pastaba: Tai padidins skenavimo trukmę.",
|
||||
"LabelSettingsFindCoversHelp": "Jei jūsų audioknyga neturi įterpto viršelio arba viršelio paveikslėlio aplanke, bandyti rasti viršelį.<br>Pastaba: Tai padidins skenavimo trukmę",
|
||||
"LabelSettingsHideSingleBookSeries": "Slėpti serijas, turinčias tik vieną knygą",
|
||||
"LabelSettingsHideSingleBookSeriesHelp": "Serijos, turinčios tik vieną knygą, bus paslėptos nuo serijų puslapio ir pagrindinio puslapio lentynų.",
|
||||
"LabelSettingsHomePageBookshelfView": "Naudoti pagrindinio puslapio knygų lentynų vaizdą",
|
||||
@@ -563,7 +563,6 @@
|
||||
"MessageItemsSelected": "Pasirinkti {0} elementai (-ų)",
|
||||
"MessageItemsUpdated": "Atnaujinti {0} elementai (-ų)",
|
||||
"MessageJoinUsOn": "Prisijunkite prie mūsų",
|
||||
"MessageListeningSessionsInTheLastYear": "{0} klausymo sesijų per paskutinius metus",
|
||||
"MessageLoading": "Kraunama...",
|
||||
"MessageLoadingFolders": "Kraunami aplankai...",
|
||||
"MessageM4BFailed": "M4B Nepavyko!",
|
||||
@@ -666,8 +665,6 @@
|
||||
"ToastChaptersMustHaveTitles": "Skyriai turi turėti pavadinimus",
|
||||
"ToastChaptersRemoved": "Skyriai pašalinti",
|
||||
"ToastCollectionItemsAddFailed": "Nepavyko pridėti į kolekciją",
|
||||
"ToastCollectionItemsAddSuccess": "Pridėta į kolekciją",
|
||||
"ToastCollectionItemsRemoveSuccess": "Elementai pašalinti iš kolekcijos",
|
||||
"ToastCollectionRemoveSuccess": "Kolekcija pašalinta",
|
||||
"ToastCollectionUpdateSuccess": "Kolekcija atnaujinta",
|
||||
"ToastCoverUpdateFailed": "Viršelio atnaujinimas nepavyko",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user