mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
Compare commits
79 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
361d20df2c | ||
|
|
ced89c5c54 | ||
|
|
a5548a5429 | ||
|
|
8f8d20a324 | ||
|
|
0f69a3a4cb | ||
|
|
9d10ed31a7 | ||
|
|
dde0169f2a | ||
|
|
a2ed7d319d | ||
|
|
475f026749 | ||
|
|
a03f1bdf7b | ||
|
|
b43046fbeb | ||
|
|
3739951b36 | ||
|
|
0f25453949 | ||
|
|
cd47fc777a | ||
|
|
f138fe31e7 | ||
|
|
454c6c7202 | ||
|
|
ce3ad4c1c7 | ||
|
|
b925f3e19d | ||
|
|
9a56b30b6c | ||
|
|
6b07fda273 | ||
|
|
727fe39e6d | ||
|
|
f8ca936ee7 | ||
|
|
fe40ede34a | ||
|
|
c23f2d3810 | ||
|
|
af66144060 | ||
|
|
ba7b82631f | ||
|
|
a166f96bdf | ||
|
|
2259e4bf1c | ||
|
|
f75ad77e85 | ||
|
|
f2913d1e83 | ||
|
|
0b3307cd70 | ||
|
|
1213309f35 | ||
|
|
5a5f8d701e | ||
|
|
bdca990e82 | ||
|
|
8081439009 | ||
|
|
80c604e089 | ||
|
|
f19d7aac1e | ||
|
|
43c1018e3e | ||
|
|
eb8bdfc94c | ||
|
|
e842a5287f | ||
|
|
e0b583ff1d | ||
|
|
5e3ca4d571 | ||
|
|
730b093a5f | ||
|
|
2f9b4e75d2 | ||
|
|
d9657587c4 | ||
|
|
69ba569b04 | ||
|
|
e850cdcd2f | ||
|
|
51bfb353e7 | ||
|
|
3f64435afa | ||
|
|
166b1ee371 | ||
|
|
0e63e7454b | ||
|
|
058af49807 | ||
|
|
7888a53dbf | ||
|
|
2ec0e295fa | ||
|
|
1776174d3f | ||
|
|
b837963f0e | ||
|
|
6b4d81e0ba | ||
|
|
caf658a7bf | ||
|
|
4a598e3908 | ||
|
|
9a6f66444d | ||
|
|
ed271fc485 | ||
|
|
9ce6258914 | ||
|
|
c6a424ee92 | ||
|
|
45a105a26f | ||
|
|
0bcf1e4743 | ||
|
|
e7b56b2bee | ||
|
|
138c0ed464 | ||
|
|
777acbbd68 | ||
|
|
3ab21ff6aa | ||
|
|
4e7c49d5d8 | ||
|
|
8b629888ff | ||
|
|
30f6d3a862 | ||
|
|
ea5a4701f2 | ||
|
|
85a33d4661 | ||
|
|
d1475864af | ||
|
|
eb8a2df3ea | ||
|
|
a333b75724 | ||
|
|
54c818e857 | ||
|
|
18ec31f28b |
93 changed files with 4454 additions and 557 deletions
2
.github/workflows/browserlist-update.yml
vendored
2
.github/workflows/browserlist-update.yml
vendored
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Configure git
|
- name: Configure git
|
||||||
|
|
|
||||||
2
.github/workflows/dispatch.yml
vendored
2
.github/workflows/dispatch.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Repository Dispatch
|
- name: Repository Dispatch
|
||||||
uses: peter-evans/repository-dispatch@v3
|
uses: peter-evans/repository-dispatch@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
||||||
repository: gotson/komga-website
|
repository: gotson/komga-website
|
||||||
|
|
|
||||||
2
.github/workflows/dockerhub_description.yml
vendored
2
.github/workflows/dockerhub_description.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: DockerHub Description
|
- name: DockerHub Description
|
||||||
uses: peter-evans/dockerhub-description@v4.0.2
|
uses: peter-evans/dockerhub-description@v5.0.0
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
|
||||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
|
|
@ -43,14 +43,14 @@ jobs:
|
||||||
version_next: ${{ steps.versions.outputs.version_next }}
|
version_next: ${{ steps.versions.outputs.version_next }}
|
||||||
should_release: ${{ steps.versions.outputs.should_release }}
|
should_release: ${{ steps.versions.outputs.should_release }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Homebrew
|
- name: Set up Homebrew
|
||||||
id: set-up-homebrew
|
id: set-up-homebrew
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
- name: Install svu
|
- name: Install svu
|
||||||
run: brew install caarlos0/tap/svu
|
run: brew install --cask caarlos0/tap/svu
|
||||||
- name: Compute next version for release
|
- name: Compute next version for release
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION_NEXT=`svu ${{ inputs.bump }}`" | tee -a $GITHUB_ENV
|
echo "VERSION_NEXT=`svu ${{ inputs.bump }}`" | tee -a $GITHUB_ENV
|
||||||
|
|
@ -72,7 +72,7 @@ jobs:
|
||||||
sudo rm -rf /usr/share/dotnet
|
sudo rm -rf /usr/share/dotnet
|
||||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|
@ -84,14 +84,14 @@ jobs:
|
||||||
if: needs.version.outputs.should_release #only redo if the version changed
|
if: needs.version.outputs.should_release #only redo if the version changed
|
||||||
run: sed -i -e "s/version=.*/version=${{ needs.version.outputs.version_next }}/" gradle.properties
|
run: sed -i -e "s/version=.*/version=${{ needs.version.outputs.version_next }}/" gradle.properties
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: komga-webui/package-lock.json
|
cache-dependency-path: komga-webui/package-lock.json
|
||||||
|
|
||||||
- name: Setup Java 21
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 21
|
||||||
java-package: 'jdk'
|
java-package: 'jdk'
|
||||||
|
|
@ -117,7 +117,7 @@ jobs:
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew :komga:prepareThymeLeaf :komga:bootJar :komga-tray:jar
|
run: ./gradlew :komga:prepareThymeLeaf :komga:bootJar :komga-tray:jar
|
||||||
|
|
@ -143,7 +143,7 @@ jobs:
|
||||||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: JReleaser Changelog output
|
- name: JReleaser Changelog output
|
||||||
if: always() && needs.version.outputs.should_release
|
if: always() && needs.version.outputs.should_release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: jreleaser-changelog
|
name: jreleaser-changelog
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -167,7 +167,7 @@ jobs:
|
||||||
echo $APPLE_PRIVATE_KEY | base64 --decode > ./secret/apple_private_key.p8
|
echo $APPLE_PRIVATE_KEY | base64 --decode > ./secret/apple_private_key.p8
|
||||||
|
|
||||||
- name: Conveyor make copied-site
|
- name: Conveyor make copied-site
|
||||||
uses: hydraulic-software/conveyor/actions/build@v18.1
|
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||||
if: inputs.conveyor-copied-site
|
if: inputs.conveyor-copied-site
|
||||||
with:
|
with:
|
||||||
command: --cache-limit=2.0 -f conveyor.ci.conf make copied-site -o ./output/site
|
command: --cache-limit=2.0 -f conveyor.ci.conf make copied-site -o ./output/site
|
||||||
|
|
@ -182,7 +182,7 @@ jobs:
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
||||||
- name: Upload Conveyor log
|
- name: Upload Conveyor log
|
||||||
if: always() && inputs.conveyor-copied-site
|
if: always() && inputs.conveyor-copied-site
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: conveyor-make-copied-site
|
name: conveyor-make-copied-site
|
||||||
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
||||||
|
|
@ -194,7 +194,7 @@ jobs:
|
||||||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: JReleaser Release output
|
- name: JReleaser Release output
|
||||||
if: always() && inputs.github_release
|
if: always() && inputs.github_release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: jreleaser-release
|
name: jreleaser-release
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -212,7 +212,7 @@ jobs:
|
||||||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: JReleaser Publish output
|
- name: JReleaser Publish output
|
||||||
if: always() && inputs.docker_release
|
if: always() && inputs.docker_release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: jreleaser-publish
|
name: jreleaser-publish
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -220,7 +220,7 @@ jobs:
|
||||||
build/jreleaser/output.properties
|
build/jreleaser/output.properties
|
||||||
|
|
||||||
- name: Conveyor - publish to Microsoft Store
|
- name: Conveyor - publish to Microsoft Store
|
||||||
uses: hydraulic-software/conveyor/actions/build@v18.1
|
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||||
if: inputs.msstore_release
|
if: inputs.msstore_release
|
||||||
with:
|
with:
|
||||||
command: --cache-limit=2.0 -f conveyor.msstore.ci.conf make ms-store-release -o ./output/msstore
|
command: --cache-limit=2.0 -f conveyor.msstore.ci.conf make ms-store-release -o ./output/msstore
|
||||||
|
|
@ -236,7 +236,7 @@ jobs:
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.B2_SECRET_ACCESS_KEY }}
|
||||||
- name: Upload Conveyor log
|
- name: Upload Conveyor log
|
||||||
if: always() && inputs.msstore_release
|
if: always() && inputs.msstore_release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: conveyor-ms-store-release
|
name: conveyor-ms-store-release
|
||||||
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
|
||||||
|
|
@ -246,7 +246,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Repository Dispatch
|
- name: Repository Dispatch
|
||||||
uses: peter-evans/repository-dispatch@v3
|
uses: peter-evans/repository-dispatch@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
||||||
repository: gotson/komga-website
|
repository: gotson/komga-website
|
||||||
|
|
|
||||||
20
.github/workflows/tests.yml
vendored
20
.github/workflows/tests.yml
vendored
|
|
@ -19,36 +19,36 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
name: Test server - ${{ matrix.os }}
|
name: Test server - ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- name: Setup Java 21
|
- name: Setup Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 21
|
||||||
java-package: 'jdk'
|
java-package: 'jdk'
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew build :komga-tray:jar
|
run: ./gradlew build :komga-tray:jar
|
||||||
|
|
||||||
- name: Upload Unit Test Results
|
- name: Upload Unit Test Results
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: test-results-${{ matrix.os }}
|
name: test-results-${{ matrix.os }}
|
||||||
path: komga/build/test-results/
|
path: komga/build/test-results/
|
||||||
|
|
||||||
- name: Upload Unit Test Reports
|
- name: Upload Unit Test Reports
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: test-reports-${{ matrix.os }}
|
name: test-reports-${{ matrix.os }}
|
||||||
path: komga/build/reports/tests/
|
path: komga/build/reports/tests/
|
||||||
|
|
||||||
- name: Publish Test Report
|
- name: Publish Test Report
|
||||||
uses: mikepenz/action-junit-report@v5
|
uses: mikepenz/action-junit-report@v6
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
|
|
@ -56,7 +56,7 @@ jobs:
|
||||||
|
|
||||||
- name: Conveyor - compute JDK module list
|
- name: Conveyor - compute JDK module list
|
||||||
if: github.event_name == 'push' && github.repository_owner == 'gotson' && contains(matrix.os, 'ubuntu')
|
if: github.event_name == 'push' && github.repository_owner == 'gotson' && contains(matrix.os, 'ubuntu')
|
||||||
uses: hydraulic-software/conveyor/actions/build@v18.1
|
uses: hydraulic-software/conveyor/actions/build@v20.0
|
||||||
with:
|
with:
|
||||||
command: -f conveyor.detect.conf -Kapp.machines=mac.aarch64 make processed-jars
|
command: -f conveyor.detect.conf -Kapp.machines=mac.aarch64 make processed-jars
|
||||||
signing_key: ${{ secrets.CONVEYOR_SIGNING_KEY }}
|
signing_key: ${{ secrets.CONVEYOR_SIGNING_KEY }}
|
||||||
|
|
@ -69,7 +69,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload JDK required modules
|
- name: Upload JDK required modules
|
||||||
if: steps.conveyor_compare.outcome == 'failure'
|
if: steps.conveyor_compare.outcome == 'failure'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: conveyor-required-jdk-modules
|
name: conveyor-required-jdk-modules
|
||||||
path: ./output/required-jdk-modules.txt
|
path: ./output/required-jdk-modules.txt
|
||||||
|
|
@ -78,8 +78,8 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Test webui builds
|
name: Test webui builds
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
|
||||||
186
CHANGELOG.md
186
CHANGELOG.md
|
|
@ -1,3 +1,189 @@
|
||||||
|
# [1.23.6](https://github.com/gotson/komga/compare/1.23.5...1.23.6) (2025-11-28)
|
||||||
|
## 🐛 Fixes
|
||||||
|
**kobo**
|
||||||
|
- proxy 401 errors on initialization ([3739951](https://github.com/gotson/komga/commits/3739951))
|
||||||
|
- prevent double URL encoding when proxying ([ce3ad4c](https://github.com/gotson/komga/commits/ce3ad4c)), closes [#2130](https://github.com/gotson/komga/issues/2130)
|
||||||
|
- proxy Content-Type headers for kobo ([b925f3e](https://github.com/gotson/komga/commits/b925f3e)), closes [#2074](https://github.com/gotson/komga/issues/2074)
|
||||||
|
|
||||||
|
**unscoped**
|
||||||
|
- properly decode cover href when generating epub cover ([f8ca936](https://github.com/gotson/komga/commits/f8ca936)), closes [#2118](https://github.com/gotson/komga/issues/2118)
|
||||||
|
|
||||||
|
## 🔄️ Changes
|
||||||
|
**kobo**
|
||||||
|
- log error responses ([454c6c7](https://github.com/gotson/komga/commits/454c6c7))
|
||||||
|
|
||||||
|
## 🛠 Build
|
||||||
|
**docker**
|
||||||
|
- use old-releases apt repo ([ba7b826](https://github.com/gotson/komga/commits/ba7b826))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- update Browserslist db ([727fe39](https://github.com/gotson/komga/commits/727fe39))
|
||||||
|
|
||||||
|
**unscoped**
|
||||||
|
- fix svu install ([9a56b30](https://github.com/gotson/komga/commits/9a56b30))
|
||||||
|
|
||||||
|
## 📝 Documentation
|
||||||
|
**api**
|
||||||
|
- fix mediatype ([af66144](https://github.com/gotson/komga/commits/af66144))
|
||||||
|
|
||||||
|
## 🌐 Translation
|
||||||
|
**komga-tray**
|
||||||
|
- translated using Weblate (Arabic) ([a5548a5](https://github.com/gotson/komga/commits/a5548a5))
|
||||||
|
- translated using Weblate (Russian) ([8f8d20a](https://github.com/gotson/komga/commits/8f8d20a))
|
||||||
|
- translated using Weblate (Galician) ([0f69a3a](https://github.com/gotson/komga/commits/0f69a3a))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- translated using Weblate (Croatian) ([dde0169](https://github.com/gotson/komga/commits/dde0169))
|
||||||
|
- translated using Weblate (Russian) ([a2ed7d3](https://github.com/gotson/komga/commits/a2ed7d3))
|
||||||
|
- translated using Weblate (Portuguese (Brazil)) ([475f026](https://github.com/gotson/komga/commits/475f026))
|
||||||
|
- translated using Weblate (Thai) ([a03f1bd](https://github.com/gotson/komga/commits/a03f1bd))
|
||||||
|
|
||||||
|
## ⚙️ Dependencies
|
||||||
|
**ci**
|
||||||
|
- bump actions/checkout from 5 to 6 ([f138fe3](https://github.com/gotson/komga/commits/f138fe3))
|
||||||
|
- bump mikepenz/action-junit-report from 5 to 6 ([6b07fda](https://github.com/gotson/komga/commits/6b07fda))
|
||||||
|
- bump actions/upload-artifact from 4 to 5 ([fe40ede](https://github.com/gotson/komga/commits/fe40ede))
|
||||||
|
- bump actions/setup-node from 5 to 6 ([c23f2d3](https://github.com/gotson/komga/commits/c23f2d3))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- bump node-forge from 1.3.1 to 1.3.2 in /komga-webui ([0f25453](https://github.com/gotson/komga/commits/0f25453))
|
||||||
|
- bump js-yaml from 3.14.1 to 3.14.2 in /komga-webui ([cd47fc7](https://github.com/gotson/komga/commits/cd47fc7))
|
||||||
|
|
||||||
|
# [1.23.5](https://github.com/gotson/komga/compare/1.23.4...1.23.5) (2025-10-08)
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- support local artwork in gif format ([f19d7aa](https://github.com/gotson/komga/commits/f19d7aa)), closes [#1853](https://github.com/gotson/komga/issues/1853)
|
||||||
|
|
||||||
|
## 🐛 Fixes
|
||||||
|
**api**
|
||||||
|
- empty content when x-api-key is sent alongside session ([5a5f8d7](https://github.com/gotson/komga/commits/5a5f8d7)), closes [#2099](https://github.com/gotson/komga/issues/2099)
|
||||||
|
- relax JSON deserializer ([eb8bdfc](https://github.com/gotson/komga/commits/eb8bdfc))
|
||||||
|
- add id field in HistoricalEventDto ([5e3ca4d](https://github.com/gotson/komga/commits/5e3ca4d))
|
||||||
|
|
||||||
|
## 🏎 Perf
|
||||||
|
**api**
|
||||||
|
- remove no-transform cache-control from response header ([43c1018](https://github.com/gotson/komga/commits/43c1018)), closes [#2091](https://github.com/gotson/komga/issues/2091)
|
||||||
|
|
||||||
|
## 🔄️ Changes
|
||||||
|
|
||||||
|
- add more logs when epub extension is missing ([730b093](https://github.com/gotson/komga/commits/730b093))
|
||||||
|
- add more logs to koreader sync controller ([2f9b4e7](https://github.com/gotson/komga/commits/2f9b4e7))
|
||||||
|
- make dslRO transaction aware ([69ba569](https://github.com/gotson/komga/commits/69ba569))
|
||||||
|
|
||||||
|
## 🛠 Build
|
||||||
|
**webui**
|
||||||
|
- update Browserslist db ([e842a52](https://github.com/gotson/komga/commits/e842a52))
|
||||||
|
|
||||||
|
## 🌐 Translation
|
||||||
|
**komga-tray**
|
||||||
|
- translated using Weblate (Portuguese (Brazil)) ([2259e4b](https://github.com/gotson/komga/commits/2259e4b))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- translated using Weblate (Slovak) ([f75ad77](https://github.com/gotson/komga/commits/f75ad77))
|
||||||
|
- translated using Weblate (Croatian) ([f2913d1](https://github.com/gotson/komga/commits/f2913d1))
|
||||||
|
- translated using Weblate (Czech) ([0b3307c](https://github.com/gotson/komga/commits/0b3307c))
|
||||||
|
- translated using Weblate (Portuguese (Brazil)) ([1213309](https://github.com/gotson/komga/commits/1213309))
|
||||||
|
|
||||||
|
## ⚙️ Dependencies
|
||||||
|
**ci**
|
||||||
|
- bump peter-evans/dockerhub-description from 4.0.2 to 5.0.0 ([bdca990](https://github.com/gotson/komga/commits/bdca990))
|
||||||
|
- bump gradle/actions from 4 to 5 ([8081439](https://github.com/gotson/komga/commits/8081439))
|
||||||
|
- bump peter-evans/repository-dispatch from 3 to 4 ([80c604e](https://github.com/gotson/komga/commits/80c604e))
|
||||||
|
- bump hydraulic-software/conveyor from 19.0 to 20.0 ([e0b583f](https://github.com/gotson/komga/commits/e0b583f))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- bump axios from 1.8.2 to 1.12.0 in /komga-webui ([d965758](https://github.com/gotson/komga/commits/d965758))
|
||||||
|
|
||||||
|
# [1.23.4](https://github.com/gotson/komga/compare/1.23.3...1.23.4) (2025-09-09)
|
||||||
|
## 🐛 Fixes
|
||||||
|
**kobo**
|
||||||
|
- update default kobo resources ([166b1ee](https://github.com/gotson/komga/commits/166b1ee)), closes [#2066](https://github.com/gotson/komga/issues/2066)
|
||||||
|
- fail to create proxy url ([058af49](https://github.com/gotson/komga/commits/058af49)), closes [#2063](https://github.com/gotson/komga/issues/2063)
|
||||||
|
|
||||||
|
## 🏎 Perf
|
||||||
|
|
||||||
|
- send events outside of db transaction ([51bfb35](https://github.com/gotson/komga/commits/51bfb35))
|
||||||
|
|
||||||
|
## 🧪 Tests
|
||||||
|
|
||||||
|
- run tests with a WAL database instead of memorydb ([7888a53](https://github.com/gotson/komga/commits/7888a53))
|
||||||
|
|
||||||
|
## 🛠 Build
|
||||||
|
**webui**
|
||||||
|
- update Browserslist db ([0e63e74](https://github.com/gotson/komga/commits/0e63e74))
|
||||||
|
|
||||||
|
## ⚙️ Dependencies
|
||||||
|
**ci**
|
||||||
|
- bump actions/setup-node from 4 to 5 ([3f64435](https://github.com/gotson/komga/commits/3f64435))
|
||||||
|
|
||||||
|
# [1.23.3](https://github.com/gotson/komga/compare/1.23.2...1.23.3) (2025-08-28)
|
||||||
|
## 🐛 Fixes
|
||||||
|
**api**
|
||||||
|
- cannot create readlist or collection with database in WAL mode ([1776174](https://github.com/gotson/komga/commits/1776174))
|
||||||
|
|
||||||
|
## 🛠 Build
|
||||||
|
**release**
|
||||||
|
- fail jreleaser on publish errors ([6b4d81e](https://github.com/gotson/komga/commits/6b4d81e))
|
||||||
|
|
||||||
|
## ⚙️ Dependencies
|
||||||
|
**ci**
|
||||||
|
- bump actions/setup-java from 4 to 5 ([b837963](https://github.com/gotson/komga/commits/b837963))
|
||||||
|
|
||||||
|
# [1.23.2](https://github.com/gotson/komga/compare/1.23.1...1.23.2) (2025-08-25)
|
||||||
|
## 🐛 Fixes
|
||||||
|
**kobo**
|
||||||
|
- NullPointer exception ([138c0ed](https://github.com/gotson/komga/commits/138c0ed)), closes [#2045](https://github.com/gotson/komga/issues/2045)
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- ignore content negotiation when downloading page ([85a33d4](https://github.com/gotson/komga/commits/85a33d4)), closes [#2042](https://github.com/gotson/komga/issues/2042)
|
||||||
|
|
||||||
|
**unscoped**
|
||||||
|
- ignore xml namespace in EPUB opf file ([3ab21ff](https://github.com/gotson/komga/commits/3ab21ff)), closes [#2043](https://github.com/gotson/komga/issues/2043)
|
||||||
|
|
||||||
|
## 🏎 Perf
|
||||||
|
|
||||||
|
- enable SQLite WAL mode by default ([e7b56b2](https://github.com/gotson/komga/commits/e7b56b2))
|
||||||
|
|
||||||
|
## 🔄️ Changes
|
||||||
|
**api**
|
||||||
|
- mark kepubifyPath as deprecated ([d147586](https://github.com/gotson/komga/commits/d147586))
|
||||||
|
|
||||||
|
**unscoped**
|
||||||
|
- use Jsoup XmlParser instead of HTML parser where needed ([4e7c49d](https://github.com/gotson/komga/commits/4e7c49d))
|
||||||
|
|
||||||
|
## 🛠 Build
|
||||||
|
**deps**
|
||||||
|
- move redundant versions to gradle version catalog ([18ec31f](https://github.com/gotson/komga/commits/18ec31f))
|
||||||
|
|
||||||
|
## 📝 Documentation
|
||||||
|
|
||||||
|
- update sponsors ([0bcf1e4](https://github.com/gotson/komga/commits/0bcf1e4))
|
||||||
|
|
||||||
|
## 🌐 Translation
|
||||||
|
**komga-tray**
|
||||||
|
- translated using Weblate (Slovak) ([4a598e3](https://github.com/gotson/komga/commits/4a598e3))
|
||||||
|
- translated using Weblate (Assamese) ([9ce6258](https://github.com/gotson/komga/commits/9ce6258))
|
||||||
|
- added translation using Weblate (Slovak) ([c6a424e](https://github.com/gotson/komga/commits/c6a424e))
|
||||||
|
- translated using Weblate (Ukrainian) ([45a105a](https://github.com/gotson/komga/commits/45a105a))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- translated using Weblate (Slovak) ([9a6f664](https://github.com/gotson/komga/commits/9a6f664))
|
||||||
|
- translated using Weblate (Ukrainian) ([ed271fc](https://github.com/gotson/komga/commits/ed271fc))
|
||||||
|
|
||||||
|
## ⚙️ Dependencies
|
||||||
|
**ci**
|
||||||
|
- bump actions/checkout from 4 to 5 ([ea5a470](https://github.com/gotson/komga/commits/ea5a470))
|
||||||
|
- bump hydraulic-software/conveyor from 18.1 to 19.0 ([a333b75](https://github.com/gotson/komga/commits/a333b75))
|
||||||
|
|
||||||
|
**webui**
|
||||||
|
- bump brace-expansion from 1.1.11 to 1.1.12 in /komga-webui ([777acbb](https://github.com/gotson/komga/commits/777acbb))
|
||||||
|
- bump ws in /komga-webui ([30f6d3a](https://github.com/gotson/komga/commits/30f6d3a))
|
||||||
|
|
||||||
|
**unscoped**
|
||||||
|
- bump jsoup to 1.21.1 ([8b62988](https://github.com/gotson/komga/commits/8b62988))
|
||||||
|
- bump nightcompress from 1.1.0 to 1.1.1 ([eb8a2df](https://github.com/gotson/komga/commits/eb8a2df))
|
||||||
|
- bump ktlint from 1.6.0 to 1.7.1 ([54c818e](https://github.com/gotson/komga/commits/54c818e))
|
||||||
|
|
||||||
# [1.23.1](https://github.com/gotson/komga/compare/1.23.0...1.23.1) (2025-08-01)
|
# [1.23.1](https://github.com/gotson/komga/compare/1.23.0...1.23.1) (2025-08-01)
|
||||||
## 🐛 Fixes
|
## 🐛 Fixes
|
||||||
**api**
|
**api**
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,12 @@ Check the [development guidelines](./DEVELOPING.md).
|
||||||
|
|
||||||
[](https://www.jetbrains.com/?from=Komga)
|
[](https://www.jetbrains.com/?from=Komga)
|
||||||
|
|
||||||
|
Thanks to [JetBrains](https://www.jetbrains.com/?from=Komga) for providing the development environment that helps us develop Komga.
|
||||||
|
|
||||||
|
[](https://www.chromatic.com)
|
||||||
|
|
||||||
|
Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
The Komga icon is based on an icon made by [Freepik](https://www.freepik.com/home) from www.flaticon.com
|
The Komga icon is based on an icon made by [Freepik](https://www.freepik.com/home) from www.flaticon.com
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
|
configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
|
||||||
version = "1.6.0"
|
version = "1.7.1"
|
||||||
filter {
|
filter {
|
||||||
exclude("**/generated-src/**")
|
exclude("**/generated-src/**")
|
||||||
exclude("**/generated/**")
|
exclude("**/generated/**")
|
||||||
|
|
@ -164,7 +164,7 @@ jreleaser {
|
||||||
packagers {
|
packagers {
|
||||||
docker {
|
docker {
|
||||||
active = Active.RELEASE
|
active = Active.RELEASE
|
||||||
continueOnError = true
|
continueOnError = false
|
||||||
templateDirectory = rootDir.resolve("komga/docker")
|
templateDirectory = rootDir.resolve("komga/docker")
|
||||||
repository.active = Active.NEVER
|
repository.active = Active.NEVER
|
||||||
buildArgs = listOf("--cache-from", "gotson/komga:latest")
|
buildArgs = listOf("--cache-from", "gotson/komga:latest")
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
version=1.23.1
|
version=1.23.6
|
||||||
org.gradle.jvmargs=-Xmx2G
|
org.gradle.jvmargs=-Xmx2G
|
||||||
|
|
|
||||||
10
gradle/libs.versions.toml
Normal file
10
gradle/libs.versions.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[versions]
|
||||||
|
sqliteJdbc = "3.50.2.0"
|
||||||
|
nightmonkeys = "1.0.0"
|
||||||
|
twelvemonkeys = "3.12.0"
|
||||||
|
springboot = "3.5.4"
|
||||||
|
lucene = "9.9.1" # v10 requires JDK 21
|
||||||
|
jooq = "3.19.24" # should be aligned with the version provided by Spring Boot
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
gradleGitProperties = {id = "com.gorylenko.gradle-git-properties", version = "2.5.2"}
|
||||||
|
|
@ -5,7 +5,7 @@ plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
kotlin("plugin.spring")
|
kotlin("plugin.spring")
|
||||||
}
|
}
|
||||||
id("com.gorylenko.gradle-git-properties") version "2.5.2"
|
alias(libs.plugins.gradleGitProperties)
|
||||||
id("org.jetbrains.compose") version "1.8.2"
|
id("org.jetbrains.compose") version "1.8.2"
|
||||||
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0"
|
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0"
|
||||||
id("dev.hydraulic.conveyor") version "1.12"
|
id("dev.hydraulic.conveyor") version "1.12"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
dialog_error.close=إغلاق
|
||||||
|
dialog_error.copy_clipboard=النسخ إلى الحافظة
|
||||||
|
dialog_error.title=Komga لم يقدر على البدء
|
||||||
|
error_message.port_in_use=الباب {} على قيد الاستعمال.\nربما Komga جارٍ بالفعل.\nتحقق أيقونة علبة النظام أو القائمة لأيقونة Komga.
|
||||||
|
error_message.unexpected=حصل خطأ غير متوقع.
|
||||||
|
menu.open_komga=فتح Komga
|
||||||
|
menu.quit=إغلاق Komga
|
||||||
|
menu.show_conf_dir=فتح موقع الإعدادات
|
||||||
|
menu.show_log=إظهار ملف السجل
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
dialog_error.close=বন্ধ কৰক
|
dialog_error.close=বন্ধ কৰক
|
||||||
dialog_error.copy_clipboard=ক্লিপবোর্ডলৈ কপি কৰক
|
dialog_error.copy_clipboard=ক্লিপব’ৰ্ডলৈ কপি কৰক
|
||||||
dialog_error.title=Komga আৰম্ভ কৰাত ব্যৰ্থ হ’ল
|
dialog_error.title=কমগা আৰম্ভ কৰাত বিফল
|
||||||
error_message.port_in_use={} পৰ্ট ইতিমধ্যে ব্যৱহাৰ কৰা হৈছে।\nKomga চাগে ইতিমধ্যে চলি আছে।\nKomga আইকনৰ বাবে ট্ৰে আইকন বা মেনু বাৰ পৰীক্ষা কৰক।
|
error_message.port_in_use={} প’ৰ্ট ইতিমধ্যে ব্যৱহৃত।\nকমগা সম্ভৱতঃ ইতিমধ্যে চলি আছে।\nকমগা আইকনৰ বাবে ট্ৰে আইকন বা মেনু বাৰ পৰীক্ষা কৰক।
|
||||||
error_message.unexpected=এটা অপ্ৰত্যাশিত ভুল ঘটিল।
|
error_message.unexpected=এক অপ্ৰত্যাশিত ত্ৰুটি ঘটিল।
|
||||||
menu.open_komga=Komga খুলিব
|
menu.open_komga=কমগা খোলক
|
||||||
menu.quit=Komga এৰি দিয়ক
|
menu.quit=কমগা বন্ধ কৰক
|
||||||
menu.show_conf_dir=বিন্যাস পঞ্জিকা খোলক
|
menu.show_conf_dir=বিন্যাস ডাইৰেক্টৰি খোলক
|
||||||
menu.show_log=লগ ফাইল দেখুৱাওক
|
menu.show_log=লগ ফাইল দেখুৱাওক
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
dialog_error.close=Pechar
|
||||||
|
dialog_error.copy_clipboard=Copiar ao portapapeis
|
||||||
|
dialog_error.title=Komga fallou ao iniciar
|
||||||
|
error_message.port_in_use=O porto {} está en uso.\nÉ probable que Komga xa esté a executarse.\nBusca a icona de Komga na bandexa de sistema ou a barra de menú.
|
||||||
|
error_message.unexpected=Aconteceu un erro imprevisto.
|
||||||
|
menu.open_komga=Abrir Komga
|
||||||
|
menu.quit=Saír de Komga
|
||||||
|
menu.show_conf_dir=Abrir o cartafol de configuración
|
||||||
|
menu.show_log=Amosar o ficheiro de rexistro
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
dialog_error.close=Fechar
|
||||||
|
dialog_error.copy_clipboard=Copiar para área de transferência
|
||||||
|
dialog_error.title=Komga falhou ao inicializar
|
||||||
|
error_message.port_in_use=A porta {} já está em uso.\nProvavelmente o Komga já está rodando.\nVerifique o ícone na barra de tarefas ou a barra de menu.
|
||||||
|
error_message.unexpected=Ocorreu um erro inesperado.
|
||||||
|
menu.open_komga=Abrir Komga
|
||||||
|
menu.quit=Sair do Komga
|
||||||
|
menu.show_conf_dir=Abrir configuração de diretório
|
||||||
|
menu.show_log=Mostrar arquivo de logs
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
dialog_error.close=Закрыть
|
dialog_error.close=Закрыть
|
||||||
dialog_error.copy_clipboard=Скопировать в буфер обмена
|
dialog_error.copy_clipboard=Скопировать в буфер обмена
|
||||||
dialog_error.title=Komga не смог запуститься
|
dialog_error.title=Komga не удалось запустить
|
||||||
error_message.port_in_use=Порт {] уже используется.\nKomga возможно уже работает.\nПроверьте панель задач или меню на наличие иконки Komga.
|
error_message.port_in_use=Порт {} уже используется.\nВероятно, Komga уже запущен.\nПроверьте область уведомлений или панель меню на наличие иконки Komga.
|
||||||
error_message.unexpected=Произошла непредвиденная ошибка.
|
error_message.unexpected=Произошла непредвиденная ошибка.
|
||||||
menu.open_komga=Открыть Komga
|
menu.open_komga=Открыть Komga
|
||||||
menu.quit=Закрыть Komga
|
menu.quit=Закрыть Komga
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
dialog_error.close=Zavrieť
|
||||||
|
dialog_error.copy_clipboard=Skopírovať do schránky
|
||||||
|
dialog_error.title=Aplikáciu Komga sa nepodarilo spustiť
|
||||||
|
error_message.port_in_use=Port {} sa aktuálne používa.\nAplikácia Komga je pravdepodobne už spustená.\nSkontrolujte, či ikona Komga už nie je v systémovej lište alebo medzi schovanými ikonami.
|
||||||
|
error_message.unexpected=Nastala neočakávaná chyba.
|
||||||
|
menu.open_komga=Otvoriť aplikáciu Komga
|
||||||
|
menu.quit=Zavrieť aplikáciu Komga
|
||||||
|
menu.show_conf_dir=Otvoriť konfiguračný priečinok
|
||||||
|
menu.show_log=Zobraziť logy
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
dialog_error.close=Закрити
|
dialog_error.close=Закрити
|
||||||
|
dialog_error.copy_clipboard=Копіювати в буфер обміну
|
||||||
dialog_error.title=Помилка при запуску Komga
|
dialog_error.title=Помилка при запуску Komga
|
||||||
error_message.port_in_use=Порт {} вже використовується.\nKomga напевно вже запущена.\nПеревірте панель запущених програм на наявність іконки Komga.
|
error_message.port_in_use=Порт {} вже використовується.\nKomga напевно вже запущена.\nПеревірте панель запущених програм на наявність іконки Komga.
|
||||||
error_message.unexpected=Сталася невідома помилка.
|
error_message.unexpected=Сталася невідома помилка.
|
||||||
|
|
|
||||||
375
komga-webui/package-lock.json
generated
375
komga-webui/package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
|
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
|
||||||
"@saekitominaga/isbn-verify": "^2.0.1",
|
"@saekitominaga/isbn-verify": "^2.0.1",
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.12.0",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
|
@ -5102,13 +5102,12 @@
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.8.2",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
||||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.4",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -5512,9 +5511,9 @@
|
||||||
"integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="
|
"integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
|
|
@ -5715,6 +5714,18 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/callsite": {
|
"node_modules/callsite": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||||
|
|
@ -5768,9 +5779,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001731",
|
"version": "1.0.30001757",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz",
|
||||||
"integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
|
"integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|
@ -7288,6 +7299,19 @@
|
||||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
|
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/duplexer": {
|
"node_modules/duplexer": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||||
|
|
@ -7371,9 +7395,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/editorconfig/node_modules/brace-expansion": {
|
"node_modules/editorconfig/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
|
|
@ -7614,12 +7638,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es-define-property": {
|
"node_modules/es-define-property": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"dependencies": {
|
|
||||||
"get-intrinsic": "^1.2.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
|
|
@ -7638,15 +7659,26 @@
|
||||||
"integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
|
"integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/es-set-tostringtag": {
|
"node_modules/es-object-atoms": {
|
||||||
"version": "2.0.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"get-intrinsic": "^1.1.3",
|
"es-errors": "^1.3.0"
|
||||||
"has": "^1.0.3",
|
},
|
||||||
"has-tostringtag": "^1.0.0"
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -8906,9 +8938,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/filehound/node_modules/brace-expansion": {
|
"node_modules/filehound/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
|
@ -9240,12 +9272,14 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -9406,15 +9440,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.2.4",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
"function-bind": "^1.1.2",
|
"function-bind": "^1.1.2",
|
||||||
"has-proto": "^1.0.1",
|
"get-proto": "^1.0.1",
|
||||||
"has-symbols": "^1.0.3",
|
"gopd": "^1.2.0",
|
||||||
"hasown": "^2.0.0"
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -9432,6 +9471,18 @@
|
||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-stream": {
|
"node_modules/get-stream": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||||
|
|
@ -9549,11 +9600,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
"dependencies": {
|
"engines": {
|
||||||
"get-intrinsic": "^1.1.3"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
|
@ -9657,6 +9708,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
|
|
@ -9665,9 +9717,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.0.3",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
|
|
@ -9676,11 +9728,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-tostringtag": {
|
"node_modules/has-tostringtag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.2"
|
"has-symbols": "^1.0.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -12915,9 +12967,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/js-beautify/node_modules/brace-expansion": {
|
"node_modules/js-beautify/node_modules/brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
|
|
@ -12974,9 +13026,9 @@
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
|
|
@ -13683,6 +13735,14 @@
|
||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mdn-data": {
|
"node_modules/mdn-data": {
|
||||||
"version": "2.0.30",
|
"version": "2.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||||
|
|
@ -14101,9 +14161,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz",
|
||||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
"integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6.13.0"
|
"node": ">= 6.13.0"
|
||||||
|
|
@ -19404,9 +19464,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/ws": {
|
"node_modules/webpack-dev-server/node_modules/ws": {
|
||||||
"version": "8.14.1",
|
"version": "8.18.3",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||||
"integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==",
|
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
|
@ -19657,9 +19717,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "7.5.9",
|
"version": "7.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
|
||||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.3.0"
|
"node": ">=8.3.0"
|
||||||
|
|
@ -23587,12 +23647,12 @@
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.8.2",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
||||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.4",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -23911,9 +23971,9 @@
|
||||||
"integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="
|
"integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
|
|
@ -24043,6 +24103,15 @@
|
||||||
"set-function-length": "^1.2.1"
|
"set-function-length": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"requires": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"callsite": {
|
"callsite": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||||
|
|
@ -24084,9 +24153,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001731",
|
"version": "1.0.30001757",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz",
|
||||||
"integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg=="
|
"integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ=="
|
||||||
},
|
},
|
||||||
"case-sensitive-paths-webpack-plugin": {
|
"case-sensitive-paths-webpack-plugin": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
|
|
@ -25214,6 +25283,16 @@
|
||||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
|
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"requires": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||||
|
|
@ -25290,9 +25369,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
|
|
@ -25489,12 +25568,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es-define-property": {
|
"es-define-property": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
|
||||||
"requires": {
|
|
||||||
"get-intrinsic": "^1.2.4"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"es-errors": {
|
"es-errors": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
|
|
@ -25507,15 +25583,23 @@
|
||||||
"integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
|
"integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"es-set-tostringtag": {
|
"es-object-atoms": {
|
||||||
"version": "2.0.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"get-intrinsic": "^1.1.3",
|
"es-errors": "^1.3.0"
|
||||||
"has": "^1.0.3",
|
}
|
||||||
"has-tostringtag": "^1.0.0"
|
},
|
||||||
|
"es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"requires": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es-shim-unscopables": {
|
"es-shim-unscopables": {
|
||||||
|
|
@ -26462,9 +26546,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
|
@ -26700,12 +26784,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -26818,15 +26904,20 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"get-intrinsic": {
|
"get-intrinsic": {
|
||||||
"version": "1.2.4",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
"function-bind": "^1.1.2",
|
"function-bind": "^1.1.2",
|
||||||
"has-proto": "^1.0.1",
|
"get-proto": "^1.0.1",
|
||||||
"has-symbols": "^1.0.3",
|
"gopd": "^1.2.0",
|
||||||
"hasown": "^2.0.0"
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"get-package-type": {
|
"get-package-type": {
|
||||||
|
|
@ -26835,6 +26926,15 @@
|
||||||
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
|
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"requires": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"get-stream": {
|
"get-stream": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||||
|
|
@ -26919,12 +27019,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gopd": {
|
"gopd": {
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
|
||||||
"requires": {
|
|
||||||
"get-intrinsic": "^1.1.3"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
|
|
@ -26998,19 +27095,20 @@
|
||||||
"has-proto": {
|
"has-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
|
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"has-symbols": {
|
"has-symbols": {
|
||||||
"version": "1.0.3",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
|
||||||
},
|
},
|
||||||
"has-tostringtag": {
|
"has-tostringtag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-symbols": "^1.0.2"
|
"has-symbols": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hash-sum": {
|
"hash-sum": {
|
||||||
|
|
@ -29358,9 +29456,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
|
|
@ -29407,9 +29505,9 @@
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
|
|
@ -29975,6 +30073,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.4.tgz",
|
||||||
"integrity": "sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw=="
|
"integrity": "sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw=="
|
||||||
},
|
},
|
||||||
|
"math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
|
||||||
|
},
|
||||||
"mdn-data": {
|
"mdn-data": {
|
||||||
"version": "2.0.30",
|
"version": "2.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||||
|
|
@ -30295,9 +30398,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-forge": {
|
"node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz",
|
||||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
"integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
|
|
@ -34187,9 +34290,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "8.14.1",
|
"version": "8.18.3",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||||
"integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==",
|
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
}
|
}
|
||||||
|
|
@ -34354,9 +34457,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "7.5.9",
|
"version": "7.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
|
||||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
|
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
|
||||||
"@saekitominaga/isbn-verify": "^2.0.1",
|
"@saekitominaga/isbn-verify": "^2.0.1",
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.12.0",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,15 @@
|
||||||
},
|
},
|
||||||
"account_settings": {
|
"account_settings": {
|
||||||
"account_settings": "إعدادات الحساب",
|
"account_settings": "إعدادات الحساب",
|
||||||
"change_password": "تغيير كلمة السر"
|
"api_key": {
|
||||||
|
"created_date": "تاريخ الصنع: {date}",
|
||||||
|
"force_kobo_sync": "إجبار مزامنة Kobo",
|
||||||
|
"generate_api_key": "توليد مفتاح API",
|
||||||
|
"no_keys": "لم يخلق مفتاح API بعد"
|
||||||
|
},
|
||||||
|
"change_password": "تغيير كلمة السر",
|
||||||
|
"details": "تفاصيل",
|
||||||
|
"my_account": "حسابي"
|
||||||
},
|
},
|
||||||
"announcements": {
|
"announcements": {
|
||||||
"mark_all_read": "اشر عليها بانها قرأت",
|
"mark_all_read": "اشر عليها بانها قرأت",
|
||||||
|
|
@ -27,6 +35,7 @@
|
||||||
"tab_title": "إعلانات"
|
"tab_title": "إعلانات"
|
||||||
},
|
},
|
||||||
"authentication_activity": {
|
"authentication_activity": {
|
||||||
|
"api_key": "مفتاح API",
|
||||||
"datetime": "التاريخ والوقت",
|
"datetime": "التاريخ والوقت",
|
||||||
"email": "البريد الإلكتروني",
|
"email": "البريد الإلكتروني",
|
||||||
"error": "خطأ",
|
"error": "خطأ",
|
||||||
|
|
@ -85,7 +94,8 @@
|
||||||
"bookreader": {
|
"bookreader": {
|
||||||
"beginning_of_book": "أنت في بداية الكتاب.",
|
"beginning_of_book": "أنت في بداية الكتاب.",
|
||||||
"changing_reading_direction": "تغيير اتجاه القراءة إلى",
|
"changing_reading_direction": "تغيير اتجاه القراءة إلى",
|
||||||
"cycling_page_layout": "تخطيط دوري للصفحة",
|
"cycling_page_layout": "تغيير تخطيط الصفحة",
|
||||||
|
"cycling_page_margin": "تغيير هامش الصفحة",
|
||||||
"cycling_scale": "تغيير حجم التحرير",
|
"cycling_scale": "تغيير حجم التحرير",
|
||||||
"cycling_side_padding": "تغيير الحدود الجانبية",
|
"cycling_side_padding": "تغيير الحدود الجانبية",
|
||||||
"download_current_page": "تنزيل الصفحة الحالية",
|
"download_current_page": "تنزيل الصفحة الحالية",
|
||||||
|
|
@ -128,6 +138,7 @@
|
||||||
"general": "إعدادات عامة",
|
"general": "إعدادات عامة",
|
||||||
"gestures": "الإيماءات",
|
"gestures": "الإيماءات",
|
||||||
"page_layout": "تخطيط الصفحة",
|
"page_layout": "تخطيط الصفحة",
|
||||||
|
"page_margin": "هامش الصفحة",
|
||||||
"paged": "خيارات القارئ المرقم",
|
"paged": "خيارات القارئ المرقم",
|
||||||
"reading_mode": "وضع القراءة",
|
"reading_mode": "وضع القراءة",
|
||||||
"scale_type": "نوع القياس",
|
"scale_type": "نوع القياس",
|
||||||
|
|
@ -137,8 +148,9 @@
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"close": "إغلاق",
|
"close": "إغلاق",
|
||||||
"cycle_page_layout": "دورة تخطيط الصفحة",
|
"cycle_page_layout": "تغيير تخطيط الصفحة",
|
||||||
"cycle_scale": "مقياس الدورة",
|
"cycle_page_margin": "تغيير هامش الصفحة",
|
||||||
|
"cycle_scale": "تغيير الحجم",
|
||||||
"cycle_side_padding": "تغيير الحدود الجانبية",
|
"cycle_side_padding": "تغيير الحدود الجانبية",
|
||||||
"first_page": "الصفحة الأولى",
|
"first_page": "الصفحة الأولى",
|
||||||
"fullscreen": "إدخال/إنهاء ملء الشاشة",
|
"fullscreen": "إدخال/إنهاء ملء الشاشة",
|
||||||
|
|
@ -161,6 +173,8 @@
|
||||||
},
|
},
|
||||||
"browse_book": {
|
"browse_book": {
|
||||||
"comment": "تعليق",
|
"comment": "تعليق",
|
||||||
|
"date_created": "صُنِع",
|
||||||
|
"date_modified": "آخر تعديل",
|
||||||
"download_file": "تحميل الملف",
|
"download_file": "تحميل الملف",
|
||||||
"file": "ملف",
|
"file": "ملف",
|
||||||
"format": "صيغة",
|
"format": "صيغة",
|
||||||
|
|
@ -170,6 +184,8 @@
|
||||||
"outdated_tooltip": "تم تغيير ملف هذا الكتاب ، يجب إعادة تحليل هذا الكتاب",
|
"outdated_tooltip": "تم تغيير ملف هذا الكتاب ، يجب إعادة تحليل هذا الكتاب",
|
||||||
"read_book": "قراءة كتاب",
|
"read_book": "قراءة كتاب",
|
||||||
"read_incognito": "قراءة التصفح المتخفي",
|
"read_incognito": "قراءة التصفح المتخفي",
|
||||||
|
"remove_from_collection": "إزالة الكتاب من المجموعة",
|
||||||
|
"remove_from_readlist": "إزالة الكتاب من قائمة القراءة",
|
||||||
"size": "حجم"
|
"size": "حجم"
|
||||||
},
|
},
|
||||||
"browse_collection": {
|
"browse_collection": {
|
||||||
|
|
@ -184,6 +200,7 @@
|
||||||
},
|
},
|
||||||
"browse_series": {
|
"browse_series": {
|
||||||
"earliest_year_from_release_dates": "هذه هي السنة الأولى من تواريخ الإصدار لجميع الكتب في السلسلة",
|
"earliest_year_from_release_dates": "هذه هي السنة الأولى من تواريخ الإصدار لجميع الكتب في السلسلة",
|
||||||
|
"remove_from_collection": "إزالة السلسلة من المجموعة",
|
||||||
"series_no_summary": "هذه السلسلة لا تحتوي على ملخص ، لذلك اخترنا واحدًا لك!",
|
"series_no_summary": "هذه السلسلة لا تحتوي على ملخص ، لذلك اخترنا واحدًا لك!",
|
||||||
"summary_from_book": "ملخص من الكتاب {number}:"
|
"summary_from_book": "ملخص من الكتاب {number}:"
|
||||||
},
|
},
|
||||||
|
|
@ -194,6 +211,8 @@
|
||||||
"common": {
|
"common": {
|
||||||
"age": "العمر",
|
"age": "العمر",
|
||||||
"all_libraries": "كل المكتبات",
|
"all_libraries": "كل المكتبات",
|
||||||
|
"all_of": "كل من",
|
||||||
|
"any_of": "أي من",
|
||||||
"book": "كتاب",
|
"book": "كتاب",
|
||||||
"books": "كتب",
|
"books": "كتب",
|
||||||
"books_n": "لا يوجد كتاب | 1 كتاب | {count} كتب",
|
"books_n": "لا يوجد كتاب | 1 كتاب | {count} كتب",
|
||||||
|
|
@ -203,15 +222,19 @@
|
||||||
"choose_image": "اختر صورة",
|
"choose_image": "اختر صورة",
|
||||||
"close": "إغلاق",
|
"close": "إغلاق",
|
||||||
"collections": "المجموعات",
|
"collections": "المجموعات",
|
||||||
|
"copied": "تم النسخ!",
|
||||||
"create": "صنع",
|
"create": "صنع",
|
||||||
"delete": "حذف",
|
"delete": "حذف",
|
||||||
"discard": "تجاهل",
|
"dimension": "ع:{width}, ط:{height}",
|
||||||
|
"discard": "تخلص",
|
||||||
"disk_space": "مساحة القرص",
|
"disk_space": "مساحة القرص",
|
||||||
"dismiss": "رفض",
|
"dismiss": "رفض",
|
||||||
"download": "تحميل",
|
"download": "تحميل",
|
||||||
"drag_drop": "أمسك واسحب",
|
"drag_drop": "أمسك واسحب",
|
||||||
|
"duplicate": "مكرر",
|
||||||
"email": "البريد الإلكتروني",
|
"email": "البريد الإلكتروني",
|
||||||
"epub": "Epub",
|
"epub": "EPUB",
|
||||||
|
"error": "خطأ",
|
||||||
"filename": "اسم الملف",
|
"filename": "اسم الملف",
|
||||||
"filter_no_matches": "الفلتر النشط ليس له تطابق",
|
"filter_no_matches": "الفلتر النشط ليس له تطابق",
|
||||||
"genre": "نوع",
|
"genre": "نوع",
|
||||||
|
|
@ -219,13 +242,17 @@
|
||||||
"go_to_library": "اذهب إلى المكتبة",
|
"go_to_library": "اذهب إلى المكتبة",
|
||||||
"go_to_readlist": "انتقل إلى قائمة القراءة",
|
"go_to_readlist": "انتقل إلى قائمة القراءة",
|
||||||
"go_to_series": "الانتقال إلى السلسلة",
|
"go_to_series": "الانتقال إلى السلسلة",
|
||||||
|
"i_understand": "فهمت",
|
||||||
"library": "مكتبة",
|
"library": "مكتبة",
|
||||||
"locale_name": "العربية",
|
"locale_name": "العربية",
|
||||||
"locale_rtl": "true",
|
"locale_rtl": "true",
|
||||||
"lock_all": "قفل الكل",
|
"lock_all": "قفل الكل",
|
||||||
|
"media": "الوسائط",
|
||||||
|
"more": "المزيد",
|
||||||
"n_selected": "{count} مختار",
|
"n_selected": "{count} مختار",
|
||||||
"nothing_to_show": "لا شيء للعرض",
|
"nothing_to_show": "لا شيء للعرض",
|
||||||
"oneshot": "طلقة واحدة",
|
"ok": "حسنا",
|
||||||
|
"oneshot": "قصة منفردة",
|
||||||
"outdated": "متقادمة",
|
"outdated": "متقادمة",
|
||||||
"page": "صفحة",
|
"page": "صفحة",
|
||||||
"page_number": "رقم الصفحة",
|
"page_number": "رقم الصفحة",
|
||||||
|
|
@ -235,19 +262,23 @@
|
||||||
"password": "كلمة السر",
|
"password": "كلمة السر",
|
||||||
"pdf": "PDF",
|
"pdf": "PDF",
|
||||||
"pending_tasks": "لا توجد مهام معلقة | مهمة واحدة معلقة | {count} مهام معلقة",
|
"pending_tasks": "لا توجد مهام معلقة | مهمة واحدة معلقة | {count} مهام معلقة",
|
||||||
|
"pinned_libraries": "المكتبات المثبتة",
|
||||||
"publisher": "الناشر",
|
"publisher": "الناشر",
|
||||||
"read": "اقرأ",
|
"read": "اقرأ",
|
||||||
"read_on": "قرأ في {date}",
|
"read_on": "قرأ في {date}",
|
||||||
"readlist": "قائمة القراءة",
|
"readlist": "قائمة القراءة",
|
||||||
"readlists": "قوائم القراءة",
|
"readlists": "قوائم القراءة",
|
||||||
"remember-me": "تذكرني",
|
"remember-me": "تذكرني",
|
||||||
|
"reorder": "تغيير الترتيب",
|
||||||
"required": "مطلوب",
|
"required": "مطلوب",
|
||||||
"reset_filters": "إعادة تعيين فلتر",
|
"reset_filters": "إعادة تعيين فلتر",
|
||||||
"roles": "أدوار",
|
"roles": "أدوار",
|
||||||
"save_changes": "حفظ التغييرات",
|
"save_changes": "حفظ التغييرات",
|
||||||
"series": "سلسلة",
|
"series": "سلسلة",
|
||||||
|
"settings": "الإعدادات",
|
||||||
"sidecars": "Sidecars",
|
"sidecars": "Sidecars",
|
||||||
"tags": "التصنيف",
|
"tags": "التصنيف",
|
||||||
|
"ui": "واجهة المستخدم",
|
||||||
"unavailable": "غير متوفر",
|
"unavailable": "غير متوفر",
|
||||||
"unlock_all": "فتح الكل",
|
"unlock_all": "فتح الكل",
|
||||||
"url": "عنوان URL",
|
"url": "عنوان URL",
|
||||||
|
|
@ -271,10 +302,11 @@
|
||||||
"comicrack_preambule_html": "يمكنك استيراد قوائم قراءة ComicRack الحالية بتنسيق <code>cbl</code>.<br>سيحاول Komga مطابقة السلسلة ورقم الكتاب المقدمين مع السلسلة والكتب في مكتباتك.",
|
"comicrack_preambule_html": "يمكنك استيراد قوائم قراءة ComicRack الحالية بتنسيق <code>cbl</code>.<br>سيحاول Komga مطابقة السلسلة ورقم الكتاب المقدمين مع السلسلة والكتب في مكتباتك.",
|
||||||
"dialog_confirmation": {
|
"dialog_confirmation": {
|
||||||
"body": "{unmatched} / {total} الكتب غير متطابقة",
|
"body": "{unmatched} / {total} الكتب غير متطابقة",
|
||||||
|
"body2": "{duplicates} / {total} كتاب مكرر",
|
||||||
"create": "الخلق على أي حال",
|
"create": "الخلق على أي حال",
|
||||||
"title": "بعض الكتب لا تتطابق"
|
"title": "بعض الكتب لا تتطابق"
|
||||||
},
|
},
|
||||||
"field_file_label": "ComicRack Reading List (.cbl)",
|
"field_file_label": "قائمة قراءة ComicRack (من نوع cbl.)",
|
||||||
"field_files_label": "قوائم القراءة ComicRack (.cbl)",
|
"field_files_label": "قوائم القراءة ComicRack (.cbl)",
|
||||||
"import_read_lists": "استيراد قوائم القراءة",
|
"import_read_lists": "استيراد قوائم القراءة",
|
||||||
"imported_as": "مستورد كـ {name}",
|
"imported_as": "مستورد كـ {name}",
|
||||||
|
|
@ -286,6 +318,14 @@
|
||||||
"tab_title": "استيراد البيانات"
|
"tab_title": "استيراد البيانات"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
"add_api_key": {
|
||||||
|
"button_confirm": "توليد",
|
||||||
|
"context": "يمكن استعمال مفاتيح الAPI للتوثيق عبر بروتوكول Kobo Sync.",
|
||||||
|
"dialog_title": "توليد مفتاح API جديد",
|
||||||
|
"field_comment": "تعليق",
|
||||||
|
"field_comment_hint": "ما الغرض من مفتاح الAPI هذا؟",
|
||||||
|
"info_copy": "يرجى التأكد من نسخ مفتاح الAPI الآن. لا يستطاع النظر عليه مجددا!"
|
||||||
|
},
|
||||||
"add_to_collection": {
|
"add_to_collection": {
|
||||||
"button_create": "خلق",
|
"button_create": "خلق",
|
||||||
"card_collection_subtitle": "لا توجد سلسلة | 1 سلسلة | {count} سلسلة",
|
"card_collection_subtitle": "لا توجد سلسلة | 1 سلسلة | {count} سلسلة",
|
||||||
|
|
@ -319,6 +359,12 @@
|
||||||
"filter": "مصنف حسب رقم الكتاب أو العنوان أو تاريخ الإصدار",
|
"filter": "مصنف حسب رقم الكتاب أو العنوان أو تاريخ الإصدار",
|
||||||
"title": "حدد كتاب"
|
"title": "حدد كتاب"
|
||||||
},
|
},
|
||||||
|
"delete_apikey": {
|
||||||
|
"button_confirm": "حذف",
|
||||||
|
"confirm_delete": "فهمت, حذف مفتاح الAPI المسمى {name}",
|
||||||
|
"dialog_title": "حذف مفتاح الAPI",
|
||||||
|
"warning_html": "كل التطبيقات التي تستعمل مفتاح الAPI هذا ستصبح غير قادرة على الوصول إلى الAPI التابع لKomga. لا يمكن التراجع عن هذا الإجراء."
|
||||||
|
},
|
||||||
"delete_book": {
|
"delete_book": {
|
||||||
"button_confirm": "حذف",
|
"button_confirm": "حذف",
|
||||||
"confirm_delete": "نعم، حذف كتاب \"{name}\" وملفاته",
|
"confirm_delete": "نعم، حذف كتاب \"{name}\" وملفاته",
|
||||||
|
|
@ -389,6 +435,8 @@
|
||||||
"field_summary": "ملخص",
|
"field_summary": "ملخص",
|
||||||
"field_tags": "التصنيف",
|
"field_tags": "التصنيف",
|
||||||
"field_title": "العنوان",
|
"field_title": "العنوان",
|
||||||
|
"number_sort_decrement": "تقليل الجميع ب1",
|
||||||
|
"number_sort_increment": "زيادة الجميع ب1",
|
||||||
"tab_authors": "المؤلفون",
|
"tab_authors": "المؤلفون",
|
||||||
"tab_general": "إعدادات عامة",
|
"tab_general": "إعدادات عامة",
|
||||||
"tab_links": "الروابط",
|
"tab_links": "الروابط",
|
||||||
|
|
@ -415,6 +463,7 @@
|
||||||
"dialot_title_edit": "تحرير المكتبة",
|
"dialot_title_edit": "تحرير المكتبة",
|
||||||
"field_analysis_analyze_dimensions": "تحليل أبعاد الصفحات",
|
"field_analysis_analyze_dimensions": "تحليل أبعاد الصفحات",
|
||||||
"field_analysis_hash_files": "حساب تجزئة للملفات",
|
"field_analysis_hash_files": "حساب تجزئة للملفات",
|
||||||
|
"field_analysis_hash_koreader": "حسابة التلبيد لملفات KOReader",
|
||||||
"field_analysis_hash_pages": "حساب تجزئة الصفحات",
|
"field_analysis_hash_pages": "حساب تجزئة الصفحات",
|
||||||
"field_convert_to_cbz": "تحويل تلقائيا إلى CBZ",
|
"field_convert_to_cbz": "تحويل تلقائيا إلى CBZ",
|
||||||
"field_import_barcode_isbn": "الباركود ردمك",
|
"field_import_barcode_isbn": "الباركود ردمك",
|
||||||
|
|
@ -422,15 +471,19 @@
|
||||||
"field_import_comicinfo_collections": "المجموعات",
|
"field_import_comicinfo_collections": "المجموعات",
|
||||||
"field_import_comicinfo_readlists": "قوائم القراءة",
|
"field_import_comicinfo_readlists": "قوائم القراءة",
|
||||||
"field_import_comicinfo_series": "سلسلة البيانات الوصفية",
|
"field_import_comicinfo_series": "سلسلة البيانات الوصفية",
|
||||||
|
"field_import_comicinfo_series_append_volume": "إضافة المجلد إلى عنوان المسلسل",
|
||||||
"field_import_epub_book": "البيانات الوصفية للكتاب",
|
"field_import_epub_book": "البيانات الوصفية للكتاب",
|
||||||
"field_import_epub_series": "سلسلة البيانات الوصفية",
|
"field_import_epub_series": "سلسلة البيانات الوصفية",
|
||||||
"field_import_local_artwork": "الأعمال الفنية المحلية",
|
"field_import_local_artwork": "الأعمال الفنية المحلية",
|
||||||
"field_import_mylar_series": "سلسلة البيانات الوصفية",
|
"field_import_mylar_series": "سلسلة البيانات الوصفية",
|
||||||
"field_name": "الاسم",
|
"field_name": "الاسم",
|
||||||
|
"field_oneshotsdirectory": "موقع القصص المنفردة",
|
||||||
"field_repair_extensions": "إصلاح ملحقات الملفات غير الصحيحة تلقائيًا",
|
"field_repair_extensions": "إصلاح ملحقات الملفات غير الصحيحة تلقائيًا",
|
||||||
"field_root_folder": "المجلد الرئيسي",
|
"field_root_folder": "المجلد الرئيسي",
|
||||||
|
"field_scan_interval": "تكرار البحث عن الملفات",
|
||||||
"field_scanner_empty_trash_after_scan": "تفريغ المهملات تلقائيا بعد كل فحص",
|
"field_scanner_empty_trash_after_scan": "تفريغ المهملات تلقائيا بعد كل فحص",
|
||||||
"field_scanner_force_directory_modified_time": "فرض وقت تعديل الدليل",
|
"field_scanner_force_directory_modified_time": "فرض وقت تعديل الدليل",
|
||||||
|
"field_scanner_scan_startup": "البحث عن الملفات عند بدء البرنامج",
|
||||||
"field_series_cover": "غلاف السلسلة",
|
"field_series_cover": "غلاف السلسلة",
|
||||||
"file_browser_dialog_button_confirm": "إختيار",
|
"file_browser_dialog_button_confirm": "إختيار",
|
||||||
"file_browser_dialog_title": "المجلد الجذر للمكتبة",
|
"file_browser_dialog_title": "المجلد الجذر للمكتبة",
|
||||||
|
|
@ -441,11 +494,14 @@
|
||||||
"label_import_epub": "استيراد البيانات الوصفية من ملفات EPUB",
|
"label_import_epub": "استيراد البيانات الوصفية من ملفات EPUB",
|
||||||
"label_import_local": "استيراد أصول الوسائط المحلية",
|
"label_import_local": "استيراد أصول الوسائط المحلية",
|
||||||
"label_import_mylar": "استيراد البيانات الوصفية التي تم إنشاؤها بواسطة Mylar",
|
"label_import_mylar": "استيراد البيانات الوصفية التي تم إنشاؤها بواسطة Mylar",
|
||||||
|
"label_scan_directory_exclusions": "استبعاد المواقع",
|
||||||
|
"label_scan_types": "البحث عن أنواع الملفات هذه",
|
||||||
"label_scanner": "الماسح الضوئي",
|
"label_scanner": "الماسح الضوئي",
|
||||||
"label_series_cover": "غلاف السلسلة",
|
"label_series_cover": "غلاف السلسلة",
|
||||||
"tab_general": "إعدادات عامة",
|
"tab_general": "إعدادات عامة",
|
||||||
"tab_metadata": "البيانات الوصفية",
|
"tab_metadata": "البيانات الوصفية",
|
||||||
"tab_options": "الخيارات",
|
"tab_options": "الخيارات",
|
||||||
|
"tooltip_oneshotsdirectory": "يترك فارغا للتعطيل",
|
||||||
"tooltip_scanner_force_modified_time": "تمكين إذا كانت المكتبة على Google Drive",
|
"tooltip_scanner_force_modified_time": "تمكين إذا كانت المكتبة على Google Drive",
|
||||||
"tooltip_use_resources": "يمكن أن تستهلك الكثير من الموارد في مكتبات كبيرة أو أجهزة بطيئة"
|
"tooltip_use_resources": "يمكن أن تستهلك الكثير من الموارد في مكتبات كبيرة أو أجهزة بطيئة"
|
||||||
},
|
},
|
||||||
|
|
@ -453,11 +509,16 @@
|
||||||
"button_cancel": "إلغاء",
|
"button_cancel": "إلغاء",
|
||||||
"button_confirm": "حفظ التغييرات",
|
"button_confirm": "حفظ التغييرات",
|
||||||
"dialog_title": "تحرير قائمة القراءة",
|
"dialog_title": "تحرير قائمة القراءة",
|
||||||
|
"field_manual_ordering": "ترتيب يدوي",
|
||||||
"field_name": "الاسم",
|
"field_name": "الاسم",
|
||||||
"field_summary": "ملخص",
|
"field_summary": "ملخص",
|
||||||
"tab_general": "عام",
|
"tab_general": "عام",
|
||||||
"tab_poster": "ملصق"
|
"tab_poster": "ملصق"
|
||||||
},
|
},
|
||||||
|
"edit_recommended": {
|
||||||
|
"button_confirm": "حفظ التعديلات",
|
||||||
|
"button_reset": "الإعادة إلى التعديلات الأصلية"
|
||||||
|
},
|
||||||
"edit_series": {
|
"edit_series": {
|
||||||
"button_cancel": "إلغاء",
|
"button_cancel": "إلغاء",
|
||||||
"button_confirm": "حفظ التغييرات",
|
"button_confirm": "حفظ التغييرات",
|
||||||
|
|
@ -483,6 +544,7 @@
|
||||||
"tab_poster": "ملصق",
|
"tab_poster": "ملصق",
|
||||||
"tab_sharing": "مشاركة",
|
"tab_sharing": "مشاركة",
|
||||||
"tab_tags": "التصنيف",
|
"tab_tags": "التصنيف",
|
||||||
|
"tab_titles": "العناوين البديلة",
|
||||||
"tags_notice_multiple_edit": "أنت تقوم بتحرير العلامات لسلسلة متعددة. سيؤدي هذا إلى تجاوز العلامات الموجودة في كل سلسلة."
|
"tags_notice_multiple_edit": "أنت تقوم بتحرير العلامات لسلسلة متعددة. سيؤدي هذا إلى تجاوز العلامات الموجودة في كل سلسلة."
|
||||||
},
|
},
|
||||||
"edit_user": {
|
"edit_user": {
|
||||||
|
|
@ -525,6 +587,9 @@
|
||||||
},
|
},
|
||||||
"title": "اسم الوجهة"
|
"title": "اسم الوجهة"
|
||||||
},
|
},
|
||||||
|
"force_kobo_sync": {
|
||||||
|
"dialog_title": "إجبار مزامنة Kobo"
|
||||||
|
},
|
||||||
"password_change": {
|
"password_change": {
|
||||||
"button_cancel": "إلغاء",
|
"button_cancel": "إلغاء",
|
||||||
"button_confirm": "تغيير كلمة السر",
|
"button_confirm": "تغيير كلمة السر",
|
||||||
|
|
@ -541,6 +606,7 @@
|
||||||
},
|
},
|
||||||
"series_picker": {
|
"series_picker": {
|
||||||
"label_search_series": "سلسلة البحث",
|
"label_search_series": "سلسلة البحث",
|
||||||
|
"no_results": "لم يتم العثور على أي سلسلة",
|
||||||
"title": "اختيار سلسلة"
|
"title": "اختيار سلسلة"
|
||||||
},
|
},
|
||||||
"server_stop": {
|
"server_stop": {
|
||||||
|
|
@ -579,21 +645,31 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duplicate_pages": {
|
"duplicate_pages": {
|
||||||
|
"action_auto_delete_remaining": "باق إلغاء {count} أوتوماتيكيا",
|
||||||
"action_delete_auto": "حذف تلقائي",
|
"action_delete_auto": "حذف تلقائي",
|
||||||
"action_delete_manual": "حذف يدوي",
|
"action_delete_manual": "حذف يدوي",
|
||||||
"action_delete_matches": "حذف المطابقات",
|
"action_delete_matches": "حذف المطابقات",
|
||||||
"action_ignore": "تجاهل",
|
"action_ignore": "تجاهل",
|
||||||
|
"action_ignore_remaining": "تجاهل الباقي ({count})",
|
||||||
|
"action_manual_delete_remaining": "إلغاء الباقي يدويا ({count})",
|
||||||
"delete_to_save": "حذف لحفظ {size}",
|
"delete_to_save": "حذف لحفظ {size}",
|
||||||
"deleted_count": "تم حذف {count} مرة",
|
"deleted_count": "تم حذف {count} مرة",
|
||||||
|
"empty_title": "لم يتم العثور على صفحات مكررة",
|
||||||
|
"empty_title_known": "لا توجد نسخ مكررة معروف عنها",
|
||||||
"filter": {
|
"filter": {
|
||||||
"count": "عدد",
|
"count": "عدد",
|
||||||
|
"date_added": "تاريخ الإضافة",
|
||||||
|
"date_modified": "تاريخ التعديل",
|
||||||
"delete_count": "عدد الحذف",
|
"delete_count": "عدد الحذف",
|
||||||
"delete_size": "المساحة المحفوظة",
|
"delete_size": "المساحة المحفوظة",
|
||||||
|
"match_count": "عدد النتائج المتطابقة",
|
||||||
"size": "حجم",
|
"size": "حجم",
|
||||||
"total_size": "الحجم الإجمالي"
|
"total_size": "الحجم الإجمالي"
|
||||||
},
|
},
|
||||||
"info": "حذف الصفحات المكررة سيغيّر ملفاتك. احتفظ بنسخة احتياطية من ملفاتك واستخدم الحذف اليدوي قبل استخدام الحذف التلقائي.",
|
"info": "حذف الصفحات المكررة سيغيّر ملفاتك. احتفظ بنسخة احتياطية من ملفاتك واستخدم الحذف اليدوي قبل استخدام الحذف التلقائي.",
|
||||||
|
"known": "المعروفة",
|
||||||
"matches_n": "لا يوجد تطابق | 1 تطابق | {count} التطابق",
|
"matches_n": "لا يوجد تطابق | 1 تطابق | {count} التطابق",
|
||||||
|
"new": "الجديدة",
|
||||||
"saved_size": "حُفظ {size}",
|
"saved_size": "حُفظ {size}",
|
||||||
"title": "صفحات مكررة",
|
"title": "صفحات مكررة",
|
||||||
"unknown_size": "حجم مجهول"
|
"unknown_size": "حجم مجهول"
|
||||||
|
|
@ -609,6 +685,23 @@
|
||||||
"HARDLINK": "ملفات الروابط الثابتة/النسخ",
|
"HARDLINK": "ملفات الروابط الثابتة/النسخ",
|
||||||
"MOVE": "نقل الملفات"
|
"MOVE": "نقل الملفات"
|
||||||
},
|
},
|
||||||
|
"epubreader": {
|
||||||
|
"appearances": {
|
||||||
|
"day": "النهار",
|
||||||
|
"night": "الليل",
|
||||||
|
"sepia": "سيبيا"
|
||||||
|
},
|
||||||
|
"column_count": {
|
||||||
|
"auto": "أوتوماتيكي",
|
||||||
|
"one": "واحد",
|
||||||
|
"two": "اثنان"
|
||||||
|
},
|
||||||
|
"reading_direction": {
|
||||||
|
"auto": "أوتوماتيكي",
|
||||||
|
"ltr": "من اليسار إلى اليمين",
|
||||||
|
"rtl": "من اليمين إلى اليسار"
|
||||||
|
}
|
||||||
|
},
|
||||||
"historical_event_type": {
|
"historical_event_type": {
|
||||||
"BookConverted": "تمّ تحويل الكتاب",
|
"BookConverted": "تمّ تحويل الكتاب",
|
||||||
"BookFileDeleted": "تمّ مسح ملف الكتاب",
|
"BookFileDeleted": "تمّ مسح ملف الكتاب",
|
||||||
|
|
@ -616,6 +709,11 @@
|
||||||
"DuplicatePageDeleted": "تمّ حذف الصفحة المكررة",
|
"DuplicatePageDeleted": "تمّ حذف الصفحة المكررة",
|
||||||
"SeriesFolderDeleted": "تمّ حذف مجلد السلسلة"
|
"SeriesFolderDeleted": "تمّ حذف مجلد السلسلة"
|
||||||
},
|
},
|
||||||
|
"media_profile": {
|
||||||
|
"DIVINA": "DIVINA",
|
||||||
|
"EPUB": "EPUB",
|
||||||
|
"PDF": "PDF"
|
||||||
|
},
|
||||||
"media_status": {
|
"media_status": {
|
||||||
"ERROR": "خطأ",
|
"ERROR": "خطأ",
|
||||||
"OUTDATED": "قديمه",
|
"OUTDATED": "قديمه",
|
||||||
|
|
@ -634,6 +732,14 @@
|
||||||
"VERTICAL": "عمودي",
|
"VERTICAL": "عمودي",
|
||||||
"WEBTOON": "ويبتون"
|
"WEBTOON": "ويبتون"
|
||||||
},
|
},
|
||||||
|
"scan_interval": {
|
||||||
|
"DAILY": "يوميا",
|
||||||
|
"DISABLED": "معطل",
|
||||||
|
"EVERY_12H": "كل 12 ساعة",
|
||||||
|
"EVERY_6H": "كل 6 ساعات",
|
||||||
|
"HOURLY": "كل ساعة",
|
||||||
|
"WEEKLY": "كل أسبوع"
|
||||||
|
},
|
||||||
"series_cover": {
|
"series_cover": {
|
||||||
"FIRST": "أول",
|
"FIRST": "أول",
|
||||||
"LAST": "أخير"
|
"LAST": "أخير"
|
||||||
|
|
@ -645,6 +751,34 @@
|
||||||
"ONGOING": "مستمر"
|
"ONGOING": "مستمر"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"epubreader": {
|
||||||
|
"current_chapter": "الفصل الحالي",
|
||||||
|
"page_of": "الصفحة {page} من {count}",
|
||||||
|
"publisher_font": "الناشر",
|
||||||
|
"settings": {
|
||||||
|
"column_count": "عدد أعمدة",
|
||||||
|
"font_family": "الخط",
|
||||||
|
"layout": "تخطيط",
|
||||||
|
"layout_scroll": "تمرير",
|
||||||
|
"navigation_mode": "وضع التنقل",
|
||||||
|
"navigation_options": {
|
||||||
|
"both": "كلاهما",
|
||||||
|
"buttons": "أزرار",
|
||||||
|
"click": "نقر/ضغط"
|
||||||
|
},
|
||||||
|
"page_margins": "هوامش الصفحة"
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"cycle_pagination": "تغيير عدد الأعمدة",
|
||||||
|
"font_size_decrease": "تصغير الخط",
|
||||||
|
"font_size_increase": "تكبير الخط",
|
||||||
|
"menus": "القائمات",
|
||||||
|
"next": "أمام",
|
||||||
|
"previous": "خلف",
|
||||||
|
"settings": "الإعدادات",
|
||||||
|
"show_hide_toc": "إظهار/إخفاء الفهرس"
|
||||||
|
}
|
||||||
|
},
|
||||||
"error_codes": {
|
"error_codes": {
|
||||||
"ERR_1000": "تعذر الوصول إلى الملف أثناء التحليل",
|
"ERR_1000": "تعذر الوصول إلى الملف أثناء التحليل",
|
||||||
"ERR_1001": "نوع الوسائط غير مدعوم",
|
"ERR_1001": "نوع الوسائط غير مدعوم",
|
||||||
|
|
@ -667,11 +801,13 @@
|
||||||
"filter": {
|
"filter": {
|
||||||
"age_rating": "التصنيف العمري",
|
"age_rating": "التصنيف العمري",
|
||||||
"age_rating_none": "لا شيء",
|
"age_rating_none": "لا شيء",
|
||||||
|
"any": "أي",
|
||||||
"complete": "اكتمل",
|
"complete": "اكتمل",
|
||||||
"genre": "نوع",
|
"genre": "نوع",
|
||||||
"in_progress": "قيد التقدم",
|
"in_progress": "قيد التقدم",
|
||||||
"language": "اللغة",
|
"language": "اللغة",
|
||||||
"library": "المكتبة",
|
"library": "المكتبة",
|
||||||
|
"oneshot": "قصة منفردة",
|
||||||
"publisher": "الناشر",
|
"publisher": "الناشر",
|
||||||
"read": "اقرأ",
|
"read": "اقرأ",
|
||||||
"release_date": "تاريخ الاصدار",
|
"release_date": "تاريخ الاصدار",
|
||||||
|
|
@ -699,6 +835,8 @@
|
||||||
},
|
},
|
||||||
"library_navigation": {
|
"library_navigation": {
|
||||||
"browse": "تصفّح",
|
"browse": "تصفّح",
|
||||||
|
"browse_books": "كتب",
|
||||||
|
"browse_series": "سلسلات",
|
||||||
"collections": "المجموعات",
|
"collections": "المجموعات",
|
||||||
"readlists": "قوائم القراءة",
|
"readlists": "قوائم القراءة",
|
||||||
"recommended": "موصى به"
|
"recommended": "موصى به"
|
||||||
|
|
@ -730,6 +868,7 @@
|
||||||
"empty_trash": "إفراغ سلة المهملات",
|
"empty_trash": "إفراغ سلة المهملات",
|
||||||
"mark_read": "تحديد كمقروء",
|
"mark_read": "تحديد كمقروء",
|
||||||
"mark_unread": "تحديد كغير مقروء",
|
"mark_unread": "تحديد كغير مقروء",
|
||||||
|
"pin": "تثبيت",
|
||||||
"refresh_metadata": "تحديث البيانات الوصفية",
|
"refresh_metadata": "تحديث البيانات الوصفية",
|
||||||
"scan_library_files": "فحص ملفات المكتبة",
|
"scan_library_files": "فحص ملفات المكتبة",
|
||||||
"select_all": "تحديد الكل"
|
"select_all": "تحديد الكل"
|
||||||
|
|
@ -745,6 +884,9 @@
|
||||||
"libraries": "المكتبات",
|
"libraries": "المكتبات",
|
||||||
"logout": "تسجيل الخروج"
|
"logout": "تسجيل الخروج"
|
||||||
},
|
},
|
||||||
|
"no_libraries_pinned": {
|
||||||
|
"title": "لا مكتبات مثبتة"
|
||||||
|
},
|
||||||
"page_not_found": {
|
"page_not_found": {
|
||||||
"go_back_to_home_page": "العودة إلى الصفحة الرئيسية",
|
"go_back_to_home_page": "العودة إلى الصفحة الرئيسية",
|
||||||
"page_does_not_exist": "الصفحة التي تبحث عنها غير موجودة.",
|
"page_does_not_exist": "الصفحة التي تبحث عنها غير موجودة.",
|
||||||
|
|
@ -754,6 +896,12 @@
|
||||||
"less": "أقرأ أقل",
|
"less": "أقرأ أقل",
|
||||||
"more": "اقرأ أكثر"
|
"more": "اقرأ أكثر"
|
||||||
},
|
},
|
||||||
|
"readlist_import": {
|
||||||
|
"row": {
|
||||||
|
"duplicate_book": "كتاب مكرر",
|
||||||
|
"error_choose_book": "اختيار كتاب"
|
||||||
|
}
|
||||||
|
},
|
||||||
"readlists_expansion_panel": {
|
"readlists_expansion_panel": {
|
||||||
"manage_readlist": "إدارة قائمة القراءة",
|
"manage_readlist": "إدارة قائمة القراءة",
|
||||||
"title": "{name} قائمة القراءة"
|
"title": "{name} قائمة القراءة"
|
||||||
|
|
@ -775,12 +923,21 @@
|
||||||
"button_empty_trash": "إفراغ سلة المهملات لكل المكتبات",
|
"button_empty_trash": "إفراغ سلة المهملات لكل المكتبات",
|
||||||
"button_scan_libraries": "مسح جميع المكتبات",
|
"button_scan_libraries": "مسح جميع المكتبات",
|
||||||
"button_shutdown": "إيقاف التشغيل",
|
"button_shutdown": "إيقاف التشغيل",
|
||||||
|
"download_log": "تحميل ملف السجل",
|
||||||
"notification_tasks_cancelled": "لا يوجد مهام لإلغائها | تمّ إلغاء 1 مهمة | تمّ إلغاء {count} مهمة",
|
"notification_tasks_cancelled": "لا يوجد مهام لإلغائها | تمّ إلغاء 1 مهمة | تمّ إلغاء {count} مهمة",
|
||||||
"section_title": "إدارة الخادم"
|
"section_title": "إدارة الخادم"
|
||||||
},
|
},
|
||||||
"tab_title": "خادم"
|
"tab_title": "خادم",
|
||||||
|
"updates": "تحديثات"
|
||||||
},
|
},
|
||||||
"server_settings": {
|
"server_settings": {
|
||||||
|
"dialog_regenerate_thumbnails": {
|
||||||
|
"btn_alternate": "نعم، جميع الكتب",
|
||||||
|
"btn_cancel": "لا",
|
||||||
|
"btn_confirm": "نعم، لكن فقط إن كانت اكبر"
|
||||||
|
},
|
||||||
|
"label_kobo_port": "باب مزامنة Kobo الخارجي",
|
||||||
|
"label_server_port": "باب الخادم",
|
||||||
"server_settings": "إعدادات الخادم"
|
"server_settings": "إعدادات الخادم"
|
||||||
},
|
},
|
||||||
"settings_user": {
|
"settings_user": {
|
||||||
|
|
@ -795,12 +952,15 @@
|
||||||
"sort": {
|
"sort": {
|
||||||
"books_count": "عدد الكتب",
|
"books_count": "عدد الكتب",
|
||||||
"date_added": "تاريخ الإضافة",
|
"date_added": "تاريخ الإضافة",
|
||||||
|
"date_read": "تاريخ القراءة",
|
||||||
"date_updated": "تاريخ التحديث",
|
"date_updated": "تاريخ التحديث",
|
||||||
"file_name": "اسم الملف",
|
"file_name": "اسم الملف",
|
||||||
"file_size": "حجم الملف",
|
"file_size": "حجم الملف",
|
||||||
"folder_name": "اسم المجلد",
|
"folder_name": "اسم المجلد",
|
||||||
"name": "الاسم",
|
"name": "الاسم",
|
||||||
"number": "رقم",
|
"number": "رقم",
|
||||||
|
"page_count": "عدد الصفحات",
|
||||||
|
"random": "عشوائي",
|
||||||
"release_date": "تاريخ الإصدار"
|
"release_date": "تاريخ الإصدار"
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
|
|
@ -818,16 +978,36 @@
|
||||||
"tooltip_too_big": "الملف كبير جدًا!",
|
"tooltip_too_big": "الملف كبير جدًا!",
|
||||||
"tooltip_user_uploaded": "تمّ الرفع بواسطة المستخدم"
|
"tooltip_user_uploaded": "تمّ الرفع بواسطة المستخدم"
|
||||||
},
|
},
|
||||||
|
"titles_more": {
|
||||||
|
"less": "عناوين أقل",
|
||||||
|
"more": "عناوين أكثر"
|
||||||
|
},
|
||||||
|
"ui_settings": {
|
||||||
|
"general": "عام",
|
||||||
|
"section_oauth2": "OAuth2",
|
||||||
|
"series_groups": {
|
||||||
|
"alpha": "ابجدي",
|
||||||
|
"japanese": "غوجون (ياباني)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"available": "توجد تحديثات"
|
||||||
|
},
|
||||||
"user_roles": {
|
"user_roles": {
|
||||||
"ADMIN": "مدير",
|
"ADMIN": "مدير",
|
||||||
"FILE_DOWNLOAD": "تحميل الملف",
|
"FILE_DOWNLOAD": "تحميل الملف",
|
||||||
"PAGE_STREAMING": "صفحات البث",
|
"KOBO_SYNC": "مزامنة Kobo",
|
||||||
|
"KOREADER_SYNC": "مزامنة KOReader",
|
||||||
|
"PAGE_STREAMING": "بث الصفحات",
|
||||||
"USER": "مستخدم"
|
"USER": "مستخدم"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
|
"api_keys": "مفاتيح الAPI",
|
||||||
"users": "المستخدمين"
|
"users": "المستخدمين"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"one_or_more": "يجب أن يكون 1 أو أكثر",
|
||||||
|
"tcp_port": "يجب أن يكون بين 1 و 65535",
|
||||||
"zero_or_more": "يجب أن يكون 0 أو أكثر"
|
"zero_or_more": "يجب أن يكون 0 أو أكثر"
|
||||||
},
|
},
|
||||||
"welcome": {
|
"welcome": {
|
||||||
|
|
|
||||||
|
|
@ -827,7 +827,12 @@
|
||||||
"ERR_1031": "V ComicRack CBL Book chybí série nebo číslo",
|
"ERR_1031": "V ComicRack CBL Book chybí série nebo číslo",
|
||||||
"ERR_1032": "Soubor EPUB má chybný typ média",
|
"ERR_1032": "Soubor EPUB má chybný typ média",
|
||||||
"ERR_1033": "Některé položky chybí",
|
"ERR_1033": "Některé položky chybí",
|
||||||
"ERR_1034": "API key s touto poznámkou již existuje"
|
"ERR_1034": "API key s touto poznámkou již existuje",
|
||||||
|
"ERR_1035": "Chyba při získávání obsahu EPUB",
|
||||||
|
"ERR_1036": "Chyba při získávání záložek EPUB",
|
||||||
|
"ERR_1037": "CHyba při získávání seznamu stran EPUB",
|
||||||
|
"ERR_1038": "Chyba při získávání stran EPUB Divina",
|
||||||
|
"ERR_1039": "Chyba při získávání pozic EPUB"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"age_rating": "Věkové hodnocení",
|
"age_rating": "Věkové hodnocení",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,15 @@
|
||||||
},
|
},
|
||||||
"account_settings": {
|
"account_settings": {
|
||||||
"account_settings": "Configuración da conta",
|
"account_settings": "Configuración da conta",
|
||||||
"change_password": "Cambiar o contrasinal"
|
"api_key": {
|
||||||
|
"created_date": "Data de creación: {date}",
|
||||||
|
"force_kobo_sync": "Forzar a sincronización con Kobo",
|
||||||
|
"generate_api_key": "Xerar clave API",
|
||||||
|
"no_keys": "Aínda non se xerou clave API ningunha"
|
||||||
|
},
|
||||||
|
"change_password": "Cambiar o contrasinal",
|
||||||
|
"details": "Detalles",
|
||||||
|
"my_account": "A miña conta"
|
||||||
},
|
},
|
||||||
"announcements": {
|
"announcements": {
|
||||||
"mark_all_read": "Marcar todo como lido",
|
"mark_all_read": "Marcar todo como lido",
|
||||||
|
|
@ -27,6 +35,7 @@
|
||||||
"tab_title": "Avisos"
|
"tab_title": "Avisos"
|
||||||
},
|
},
|
||||||
"authentication_activity": {
|
"authentication_activity": {
|
||||||
|
"api_key": "Clave API",
|
||||||
"datetime": "Data e Hora",
|
"datetime": "Data e Hora",
|
||||||
"email": "Correo electrónico",
|
"email": "Correo electrónico",
|
||||||
"error": "Erro",
|
"error": "Erro",
|
||||||
|
|
@ -58,9 +67,159 @@
|
||||||
"button_scan": "Escanear",
|
"button_scan": "Escanear",
|
||||||
"button_select_series": "Escolle a serie",
|
"button_select_series": "Escolle a serie",
|
||||||
"field_import_path": "Importar dende un cartafol",
|
"field_import_path": "Importar dende un cartafol",
|
||||||
"info_part1": "Esta pantalla permitiralle importar arquivos que están fóra das súas bibliotecas existentes. Só pódese importar arquivos a series que xa existan, nese caso Komga moverá ou copiará os arquivos cara o directorio da serie escollida."
|
"info_part1": "Esta pantalla permitiralle importar arquivos que están fóra das súas bibliotecas existentes. Só pódese importar arquivos a series que xa existan, nese caso Komga moverá ou copiará os arquivos cara o directorio da serie escollida.",
|
||||||
|
"info_part2": "Se escolles un número para un libro e existe xa algún outro libro con ese número, poderás comparalos. Se decides importar o libro, Komga actualizará o existente co novo, substituindo o ficheiro existente co novo.",
|
||||||
|
"no_files_found": "Non se atoparon ficheiros",
|
||||||
|
"notification": {
|
||||||
|
"go_to_book": "Ir ao libro",
|
||||||
|
"import_failure": "Fallou a importación do libro: {file}",
|
||||||
|
"import_successful": "Libro importado con éxito: {book}",
|
||||||
|
"source_file": "Ficheiro orixe: {file}"
|
||||||
|
},
|
||||||
|
"row": {
|
||||||
|
"error_analyze_first": "É necesario analizar antes o libro",
|
||||||
|
"error_choose_series": "Escoller serie",
|
||||||
|
"error_only_import_no_errors": "Só se poden importar libros sen erros",
|
||||||
|
"warning_upgrade": "Actualizarase o libro existente"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"destination_name": "Nome de destino",
|
||||||
|
"file_name": "Nome do ficheiro",
|
||||||
|
"number": "Número",
|
||||||
|
"series": "Serie"
|
||||||
|
},
|
||||||
|
"title": "Importar",
|
||||||
|
"try_another_directory": "Tenta atopar outro directorio"
|
||||||
|
},
|
||||||
|
"bookreader": {
|
||||||
|
"beginning_of_book": "Atópaste ao principio do libro.",
|
||||||
|
"changing_reading_direction": "Trocar o sentido de lectura a",
|
||||||
|
"download_current_page": "Baixar a páxina actual",
|
||||||
|
"end_of_book": "Chegaches ao final do libro.",
|
||||||
|
"from_series_metadata": "dende os metadatos da serie",
|
||||||
|
"move_next": "Volve pulsar \"Seguinte\" para pasar ao seguinte libro.",
|
||||||
|
"move_next_exit": "Volve pulser \"Seguinte\" para saír do lector.",
|
||||||
|
"move_previous": "Volve pulsar \"Anterior\" para pasar ao libro anterior.",
|
||||||
|
"notification_poster_set_book": "A portada do libro estableceuse á páxina actual.",
|
||||||
|
"notification_poster_set_readlist": "A portada da lista de lectura estableceuse á páxina actual.",
|
||||||
|
"notification_poster_set_series": "A portada de serie estableceuse á páxina actual.",
|
||||||
|
"paged_reader_layout": {
|
||||||
|
"double": "Dobre páxina",
|
||||||
|
"double_no_cover": "Dobre páxina (sen portada)",
|
||||||
|
"single": "Páxina simple"
|
||||||
|
},
|
||||||
|
"reader_settings": "Configuración do lector",
|
||||||
|
"scale_type": {
|
||||||
|
"continuous_original": "Orixinal",
|
||||||
|
"continuous_width": "Axuste á anchura",
|
||||||
|
"height": "Axuste á altura",
|
||||||
|
"original": "Orixinal",
|
||||||
|
"screen": "Pantalla"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"always_fullscreen": "Sempre a pantalla completa",
|
||||||
|
"animate_page_transitions": "Transicións de páxina animadas",
|
||||||
|
"background_color": "Cor de fondo",
|
||||||
|
"background_colors": {
|
||||||
|
"black": "Negro",
|
||||||
|
"gray": "Gris",
|
||||||
|
"white": "Branco"
|
||||||
|
},
|
||||||
|
"general": "Xeral",
|
||||||
|
"gestures": "Xestos",
|
||||||
|
"page_layout": "Disposición de páxina",
|
||||||
|
"page_margin": "Marxe de páxina",
|
||||||
|
"reading_mode": "Modo de lectura",
|
||||||
|
"side_padding_none": "Ningún"
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"close": "Pechar",
|
||||||
|
"first_page": "Primeira páxina",
|
||||||
|
"last_page": "Derradeira páxina",
|
||||||
|
"left_to_right": "De esquerda a dereita",
|
||||||
|
"menus": "Menús",
|
||||||
|
"next_page": "Seguinte páxina",
|
||||||
|
"previous_page": "Páxina anterior",
|
||||||
|
"right_to_left": "De dereita a esquerda"
|
||||||
|
},
|
||||||
|
"tooltip_incognito": "Non se gardará o progreso de lectura"
|
||||||
|
},
|
||||||
|
"browse_book": {
|
||||||
|
"comment": "COMENTARIO",
|
||||||
|
"date_created": "CREACIÓN",
|
||||||
|
"date_modified": "ÚLTIMA MODIFICACIÓN",
|
||||||
|
"download_file": "Baixar ficheiro",
|
||||||
|
"file": "FICHEIRO",
|
||||||
|
"format": "FORMATO",
|
||||||
|
"isbn": "ISBN",
|
||||||
|
"links": "LIGAZÓNS",
|
||||||
|
"outdated_tooltip": "Cambiouse o ficheiro deste libro; é necesario volver analizalo",
|
||||||
|
"read_book": "Ler libro",
|
||||||
|
"read_incognito": "Ler de incógnito",
|
||||||
|
"remove_from_collection": "Quitar libro da colección",
|
||||||
|
"remove_from_readlist": "Quitar libro da lista de lectura",
|
||||||
|
"size": "TAMAÑO"
|
||||||
|
},
|
||||||
|
"browse_collection": {
|
||||||
|
"edit_collection": "Editar colección",
|
||||||
|
"edit_elements": "Editar elementos",
|
||||||
|
"manual_ordering": "Ordenación manual"
|
||||||
|
},
|
||||||
|
"browse_readlist": {
|
||||||
|
"edit_elements": "Editar elementos",
|
||||||
|
"edit_readlist": "Editar lista de lectura",
|
||||||
|
"manual_ordering": "Ordenación manual"
|
||||||
|
},
|
||||||
|
"browse_series": {
|
||||||
|
"earliest_year_from_release_dates": "Este é o ano máis temperán entre as datas de lanzamento de tódolos libros da serie",
|
||||||
|
"remove_from_collection": "Quitar serie da colección",
|
||||||
|
"series_no_summary": "Esta serie non ten sumario, así que escollemos un por ti!",
|
||||||
|
"summary_from_book": "Sumario do libro {number}:"
|
||||||
|
},
|
||||||
|
"collections_expansion_panel": {
|
||||||
|
"manage_collection": "Xestionar colección",
|
||||||
|
"title": "{name} colección"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"locale_name": "Galego"
|
"age": "Idade",
|
||||||
|
"all_libraries": "Tódalas bibliotecas",
|
||||||
|
"all_of": "Todo",
|
||||||
|
"any_of": "Calquera",
|
||||||
|
"book": "Libro",
|
||||||
|
"books": "Libros",
|
||||||
|
"books_n": "Ningún libro | 1 libro | {count} libros",
|
||||||
|
"books_total": "{count} / {total} libros",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"choose_image": "Escoller unha imaxe",
|
||||||
|
"close": "Pechar",
|
||||||
|
"collections": "Coleccións",
|
||||||
|
"copied": "Copiado!",
|
||||||
|
"create": "Crear",
|
||||||
|
"delete": "Borrar",
|
||||||
|
"discard": "Descartar",
|
||||||
|
"disk_space": "Espazo en disco",
|
||||||
|
"download": "Baixar",
|
||||||
|
"duplicate": "Duplicar",
|
||||||
|
"epub": "EPUB",
|
||||||
|
"error": "Erro",
|
||||||
|
"filename": "Nome de ficheiro",
|
||||||
|
"genre": "Xénero",
|
||||||
|
"go_to_collection": "Ir á colección",
|
||||||
|
"go_to_library": "Ir á biblioteca",
|
||||||
|
"go_to_readlist": "Ir á lista de lectura",
|
||||||
|
"go_to_series": "Ir á serie",
|
||||||
|
"i_understand": "Entendido",
|
||||||
|
"library": "Biblioteca",
|
||||||
|
"locale_name": "Galego",
|
||||||
|
"more": "Máis",
|
||||||
|
"nothing_to_show": "Nada que amosar",
|
||||||
|
"page": "Páxina",
|
||||||
|
"page_number": "Número de páxina",
|
||||||
|
"pages": "páxinas",
|
||||||
|
"pages_left": "Non quedan páxinas | Queda 1 páxina | Quedan {count} páxinas",
|
||||||
|
"pages_n": "Ningunha páxina | 1 páxina | {count} páxinas",
|
||||||
|
"password": "Contrasinal",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pending_tasks": "Sen tarefas pendentes | 1 tarefa pendente | {count} tarefas pendentes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
},
|
},
|
||||||
"author_roles": {
|
"author_roles": {
|
||||||
"colorist": "koloristi",
|
"colorist": "koloristi",
|
||||||
"cover": "omot",
|
"cover": "naslovnica",
|
||||||
"editor": "urednici",
|
"editor": "urednici",
|
||||||
"inker": "bojitelj",
|
"inker": "bojitelj",
|
||||||
"letterer": "tipografi",
|
"letterer": "tipografi",
|
||||||
|
|
@ -109,7 +109,7 @@
|
||||||
"notification_poster_set_series": "Trenutačna stranica je sada postavljena kao poster serije.",
|
"notification_poster_set_series": "Trenutačna stranica je sada postavljena kao poster serije.",
|
||||||
"paged_reader_layout": {
|
"paged_reader_layout": {
|
||||||
"double": "Dvije stranice",
|
"double": "Dvije stranice",
|
||||||
"double_no_cover": "Dvije stranice (bez omota)",
|
"double_no_cover": "Dvije stranice (bez naslovnice)",
|
||||||
"single": "Jedna stranica"
|
"single": "Jedna stranica"
|
||||||
},
|
},
|
||||||
"reader_settings": "Postavke čitača",
|
"reader_settings": "Postavke čitača",
|
||||||
|
|
@ -138,7 +138,7 @@
|
||||||
"general": "Općenito",
|
"general": "Općenito",
|
||||||
"gestures": "Geste",
|
"gestures": "Geste",
|
||||||
"page_layout": "Raspored stranica",
|
"page_layout": "Raspored stranica",
|
||||||
"page_margin": "Margine stranica",
|
"page_margin": "Margina stranice",
|
||||||
"paged": "Postavke prikaza stranica",
|
"paged": "Postavke prikaza stranica",
|
||||||
"reading_mode": "Modus čitanja",
|
"reading_mode": "Modus čitanja",
|
||||||
"scale_type": "Vrsta skaliranja",
|
"scale_type": "Vrsta skaliranja",
|
||||||
|
|
@ -484,7 +484,7 @@
|
||||||
"field_scanner_empty_trash_after_scan": "Automatski isprazni smeće nakon svakog pretraživanja",
|
"field_scanner_empty_trash_after_scan": "Automatski isprazni smeće nakon svakog pretraživanja",
|
||||||
"field_scanner_force_directory_modified_time": "Pretraži mape na osnovi vremena promjene",
|
"field_scanner_force_directory_modified_time": "Pretraži mape na osnovi vremena promjene",
|
||||||
"field_scanner_scan_startup": "Pretraži tijekom pokretanja",
|
"field_scanner_scan_startup": "Pretraži tijekom pokretanja",
|
||||||
"field_series_cover": "Omot serije",
|
"field_series_cover": "Naslovnica serije",
|
||||||
"file_browser_dialog_button_confirm": "Odaberi",
|
"file_browser_dialog_button_confirm": "Odaberi",
|
||||||
"file_browser_dialog_title": "Osnovna mapa biblioteke",
|
"file_browser_dialog_title": "Osnovna mapa biblioteke",
|
||||||
"label_analysis": "Analiza",
|
"label_analysis": "Analiza",
|
||||||
|
|
@ -497,7 +497,7 @@
|
||||||
"label_scan_directory_exclusions": "Isključivanja mapa",
|
"label_scan_directory_exclusions": "Isključivanja mapa",
|
||||||
"label_scan_types": "Traži ove vrste datoteka",
|
"label_scan_types": "Traži ove vrste datoteka",
|
||||||
"label_scanner": "Tražilica",
|
"label_scanner": "Tražilica",
|
||||||
"label_series_cover": "Omot serije",
|
"label_series_cover": "Naslovnica serije",
|
||||||
"tab_general": "Općenito",
|
"tab_general": "Općenito",
|
||||||
"tab_metadata": "Metapodaci",
|
"tab_metadata": "Metapodaci",
|
||||||
"tab_options": "Opcije",
|
"tab_options": "Opcije",
|
||||||
|
|
@ -780,7 +780,7 @@
|
||||||
"buttons": "Gumbovi",
|
"buttons": "Gumbovi",
|
||||||
"click": "Pritisni / Dodirni"
|
"click": "Pritisni / Dodirni"
|
||||||
},
|
},
|
||||||
"page_margins": "Margine stranica",
|
"page_margins": "Margine stranice",
|
||||||
"viewing_theme": "Tema prikaza"
|
"viewing_theme": "Tema prikaza"
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
|
|
@ -827,7 +827,12 @@
|
||||||
"ERR_1031": "ComicRack CBL knjizi nedostaje serija ili broj",
|
"ERR_1031": "ComicRack CBL knjizi nedostaje serija ili broj",
|
||||||
"ERR_1032": "EPUB datoteka sadrži neispravnu vrstu medija",
|
"ERR_1032": "EPUB datoteka sadrži neispravnu vrstu medija",
|
||||||
"ERR_1033": "Neki unosi nedostaju",
|
"ERR_1033": "Neki unosi nedostaju",
|
||||||
"ERR_1034": "API ključ s tim komentarom već postoji"
|
"ERR_1034": "API ključ s tim komentarom već postoji",
|
||||||
|
"ERR_1035": "Greška prilikom dohvaćanja tablice sadržaja EPUB-a",
|
||||||
|
"ERR_1036": "Greška prilikom dohvaćanja straničnika EPUB-a",
|
||||||
|
"ERR_1037": "Greška prilikom dohvaćanja popisa stranica EPUB-a",
|
||||||
|
"ERR_1038": "Greška prilikom dohvaćanja divina stranica EPUB-a",
|
||||||
|
"ERR_1039": "Greška prilikom dohvaćanja pozicija EPUB-a"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"age_rating": "dobna kategorija",
|
"age_rating": "dobna kategorija",
|
||||||
|
|
@ -984,7 +989,7 @@
|
||||||
"btn_confirm": "Da, ali samo ako su veće",
|
"btn_confirm": "Da, ali samo ako su veće",
|
||||||
"title": "Nanovo generiraj minijature"
|
"title": "Nanovo generiraj minijature"
|
||||||
},
|
},
|
||||||
"hint_kobo_port": "Postavi samo u slučaju problema sa sinkronizacijom omota i preuzimanja",
|
"hint_kobo_port": "Postavi samo u slučaju problema sa sinkronizacijom naslovnica i preuzimanja",
|
||||||
"label_delete_empty_collections": "Izbriši prazne zbirke nakon pretraživanja",
|
"label_delete_empty_collections": "Izbriši prazne zbirke nakon pretraživanja",
|
||||||
"label_delete_empty_readlists": "Izbriši prazne liste čitanja nakon pretraživanja",
|
"label_delete_empty_readlists": "Izbriši prazne liste čitanja nakon pretraživanja",
|
||||||
"label_kepubify_path": "Staza do kepubify",
|
"label_kepubify_path": "Staza do kepubify",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,15 @@
|
||||||
},
|
},
|
||||||
"account_settings": {
|
"account_settings": {
|
||||||
"account_settings": "Configurações de conta",
|
"account_settings": "Configurações de conta",
|
||||||
"change_password": "alterar senha"
|
"api_key": {
|
||||||
|
"created_date": "Data de criação: {date}",
|
||||||
|
"force_kobo_sync": "Forçar sincronização com Kobo",
|
||||||
|
"generate_api_key": "Gerar chave de API",
|
||||||
|
"no_keys": "Nenhuma Chave de API foi criada"
|
||||||
|
},
|
||||||
|
"change_password": "alterar senha",
|
||||||
|
"details": "Detalhes",
|
||||||
|
"my_account": "Minha conta"
|
||||||
},
|
},
|
||||||
"announcements": {
|
"announcements": {
|
||||||
"mark_all_read": "Marque todos como lido",
|
"mark_all_read": "Marque todos como lido",
|
||||||
|
|
@ -27,6 +35,7 @@
|
||||||
"tab_title": "Anúncios"
|
"tab_title": "Anúncios"
|
||||||
},
|
},
|
||||||
"authentication_activity": {
|
"authentication_activity": {
|
||||||
|
"api_key": "Chave de API",
|
||||||
"datetime": "Data e Hora",
|
"datetime": "Data e Hora",
|
||||||
"email": "E-mail",
|
"email": "E-mail",
|
||||||
"error": "Erro",
|
"error": "Erro",
|
||||||
|
|
@ -86,6 +95,7 @@
|
||||||
"beginning_of_book": "Você está no inicio do livro.",
|
"beginning_of_book": "Você está no inicio do livro.",
|
||||||
"changing_reading_direction": "Mudar Direção de Leitura para",
|
"changing_reading_direction": "Mudar Direção de Leitura para",
|
||||||
"cycling_page_layout": "Alterando Layout de Página",
|
"cycling_page_layout": "Alterando Layout de Página",
|
||||||
|
"cycling_page_margin": "Alterando Margem de Página",
|
||||||
"cycling_scale": "Alterando Escala",
|
"cycling_scale": "Alterando Escala",
|
||||||
"cycling_side_padding": "Alterando Preenchimento Lateral",
|
"cycling_side_padding": "Alterando Preenchimento Lateral",
|
||||||
"download_current_page": "Baixar a pagina atual",
|
"download_current_page": "Baixar a pagina atual",
|
||||||
|
|
@ -128,6 +138,7 @@
|
||||||
"general": "Geral",
|
"general": "Geral",
|
||||||
"gestures": "Gestos",
|
"gestures": "Gestos",
|
||||||
"page_layout": "Layout de página",
|
"page_layout": "Layout de página",
|
||||||
|
"page_margin": "Margem de página",
|
||||||
"paged": "Opções do Reader paginado",
|
"paged": "Opções do Reader paginado",
|
||||||
"reading_mode": "Modo de leitura",
|
"reading_mode": "Modo de leitura",
|
||||||
"scale_type": "Tipo de escala",
|
"scale_type": "Tipo de escala",
|
||||||
|
|
@ -138,6 +149,7 @@
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"cycle_page_layout": "Alterar layout de página",
|
"cycle_page_layout": "Alterar layout de página",
|
||||||
|
"cycle_page_margin": "Alterar margem de página",
|
||||||
"cycle_scale": "Alterar escala",
|
"cycle_scale": "Alterar escala",
|
||||||
"cycle_side_padding": "Alterar preenchimento lateral",
|
"cycle_side_padding": "Alterar preenchimento lateral",
|
||||||
"first_page": "Primeira página",
|
"first_page": "Primeira página",
|
||||||
|
|
@ -161,6 +173,8 @@
|
||||||
},
|
},
|
||||||
"browse_book": {
|
"browse_book": {
|
||||||
"comment": "COMENTÁRIO",
|
"comment": "COMENTÁRIO",
|
||||||
|
"date_created": "CRIADO",
|
||||||
|
"date_modified": "MODIFICADO POR ÚLTIMO",
|
||||||
"download_file": "Baixar arquivo",
|
"download_file": "Baixar arquivo",
|
||||||
"file": "ARQUIVO",
|
"file": "ARQUIVO",
|
||||||
"format": "FORMATO",
|
"format": "FORMATO",
|
||||||
|
|
@ -170,6 +184,8 @@
|
||||||
"outdated_tooltip": "O arquivo para este livro foi alterado, este livro deve ser reanalisado",
|
"outdated_tooltip": "O arquivo para este livro foi alterado, este livro deve ser reanalisado",
|
||||||
"read_book": "Ler livro",
|
"read_book": "Ler livro",
|
||||||
"read_incognito": "Ler incógnito",
|
"read_incognito": "Ler incógnito",
|
||||||
|
"remove_from_collection": "Remover livro da coleção",
|
||||||
|
"remove_from_readlist": "Remover livro da lista de leitura",
|
||||||
"size": "TAMANHO"
|
"size": "TAMANHO"
|
||||||
},
|
},
|
||||||
"browse_collection": {
|
"browse_collection": {
|
||||||
|
|
@ -184,6 +200,7 @@
|
||||||
},
|
},
|
||||||
"browse_series": {
|
"browse_series": {
|
||||||
"earliest_year_from_release_dates": "Este é o ano mais antigo dentre as datas de lançamento de todos os livros na série",
|
"earliest_year_from_release_dates": "Este é o ano mais antigo dentre as datas de lançamento de todos os livros na série",
|
||||||
|
"remove_from_collection": "Remover série da coleção",
|
||||||
"series_no_summary": "Esta série não contém um resumo, então escolhemos um para você!",
|
"series_no_summary": "Esta série não contém um resumo, então escolhemos um para você!",
|
||||||
"summary_from_book": "Resumo do livro {number}:"
|
"summary_from_book": "Resumo do livro {number}:"
|
||||||
},
|
},
|
||||||
|
|
@ -194,6 +211,8 @@
|
||||||
"common": {
|
"common": {
|
||||||
"age": "Idade",
|
"age": "Idade",
|
||||||
"all_libraries": "Todas as bibliotecas",
|
"all_libraries": "Todas as bibliotecas",
|
||||||
|
"all_of": "Todos",
|
||||||
|
"any_of": "Qualquer",
|
||||||
"book": "Livro",
|
"book": "Livro",
|
||||||
"books": "Livros",
|
"books": "Livros",
|
||||||
"books_n": "Nenhum livro | 1 livro | {count} livros",
|
"books_n": "Nenhum livro | 1 livro | {count} livros",
|
||||||
|
|
@ -203,6 +222,7 @@
|
||||||
"choose_image": "Escolher uma imagem",
|
"choose_image": "Escolher uma imagem",
|
||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"collections": "Coleções",
|
"collections": "Coleções",
|
||||||
|
"copied": "Copiado!",
|
||||||
"create": "Criar",
|
"create": "Criar",
|
||||||
"delete": "Excluir",
|
"delete": "Excluir",
|
||||||
"dimension": "l: {width}, a:{height}",
|
"dimension": "l: {width}, a:{height}",
|
||||||
|
|
@ -211,8 +231,10 @@
|
||||||
"dismiss": "Ignorar",
|
"dismiss": "Ignorar",
|
||||||
"download": "Baixar",
|
"download": "Baixar",
|
||||||
"drag_drop": "Arrastar e soltar",
|
"drag_drop": "Arrastar e soltar",
|
||||||
|
"duplicate": "Duplicado",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"epub": "Epub",
|
"epub": "Epub",
|
||||||
|
"error": "Erro",
|
||||||
"filename": "Nome do arquivo",
|
"filename": "Nome do arquivo",
|
||||||
"filter_no_matches": "O filtro ativo não contém correspondências",
|
"filter_no_matches": "O filtro ativo não contém correspondências",
|
||||||
"genre": "Gênero",
|
"genre": "Gênero",
|
||||||
|
|
@ -220,12 +242,17 @@
|
||||||
"go_to_library": "Ir para biblioteca",
|
"go_to_library": "Ir para biblioteca",
|
||||||
"go_to_readlist": "Ir para lista de lidos",
|
"go_to_readlist": "Ir para lista de lidos",
|
||||||
"go_to_series": "Ir para séries",
|
"go_to_series": "Ir para séries",
|
||||||
|
"i_understand": "Eu compreendo",
|
||||||
"library": "Biblioteca",
|
"library": "Biblioteca",
|
||||||
"locale_name": "Português (Brasil)",
|
"locale_name": "Português (Brasil)",
|
||||||
"locale_rtl": "false",
|
"locale_rtl": "false",
|
||||||
"lock_all": "Bloquear todos",
|
"lock_all": "Bloquear todos",
|
||||||
|
"media": "Mídia",
|
||||||
|
"more": "Mais",
|
||||||
"n_selected": "{count} selecionados",
|
"n_selected": "{count} selecionados",
|
||||||
"nothing_to_show": "Nada para exibir",
|
"nothing_to_show": "Nada para exibir",
|
||||||
|
"ok": "OK",
|
||||||
|
"oneshot": "One-shot",
|
||||||
"outdated": "Desatualizado",
|
"outdated": "Desatualizado",
|
||||||
"page": "Página",
|
"page": "Página",
|
||||||
"page_number": "Número da página",
|
"page_number": "Número da página",
|
||||||
|
|
@ -235,19 +262,23 @@
|
||||||
"password": "Senha",
|
"password": "Senha",
|
||||||
"pdf": "PDF",
|
"pdf": "PDF",
|
||||||
"pending_tasks": "Nenhuma tarefa pendente | 1 tarefa pendente | {count} tarefas pendentes",
|
"pending_tasks": "Nenhuma tarefa pendente | 1 tarefa pendente | {count} tarefas pendentes",
|
||||||
|
"pinned_libraries": "Bibliotecas Fixadas",
|
||||||
"publisher": "Editora",
|
"publisher": "Editora",
|
||||||
"read": "Ler",
|
"read": "Ler",
|
||||||
"read_on": "Lido em {date}",
|
"read_on": "Lido em {date}",
|
||||||
"readlist": "Lista de Leitura",
|
"readlist": "Lista de Leitura",
|
||||||
"readlists": "Listas de Leitura",
|
"readlists": "Listas de Leitura",
|
||||||
"remember-me": "Me lembre",
|
"remember-me": "Me lembre",
|
||||||
|
"reorder": "Reordernar",
|
||||||
"required": "Obrigatório",
|
"required": "Obrigatório",
|
||||||
"reset_filters": "Redefinir filtros",
|
"reset_filters": "Redefinir filtros",
|
||||||
"roles": "Funções",
|
"roles": "Funções",
|
||||||
"save_changes": "Salvar mudanças",
|
"save_changes": "Salvar mudanças",
|
||||||
"series": "Séries | Séries",
|
"series": "Séries | Séries",
|
||||||
|
"settings": "Configurações",
|
||||||
"sidecars": "Carrinho",
|
"sidecars": "Carrinho",
|
||||||
"tags": "Tags",
|
"tags": "Tags",
|
||||||
|
"ui": "Interface de Usuário",
|
||||||
"unavailable": "Indisponível",
|
"unavailable": "Indisponível",
|
||||||
"unlock_all": "Desbloquear tudo",
|
"unlock_all": "Desbloquear tudo",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
|
|
@ -271,6 +302,7 @@
|
||||||
"comicrack_preambule_html": "Você pode importar Listas de Leitura do ComicRack existentes no formato <code>.cbl</code><br>Komga tentará combinar a série fornecida e o número do livro com as séries e livros em suas bibliotecas.",
|
"comicrack_preambule_html": "Você pode importar Listas de Leitura do ComicRack existentes no formato <code>.cbl</code><br>Komga tentará combinar a série fornecida e o número do livro com as séries e livros em suas bibliotecas.",
|
||||||
"dialog_confirmation": {
|
"dialog_confirmation": {
|
||||||
"body": "{unmatched} / {total} livro(s) não foram marcados",
|
"body": "{unmatched} / {total} livro(s) não foram marcados",
|
||||||
|
"body2": "{duplicates} / {total} livros são duplicados",
|
||||||
"create": "Criar de todo modo",
|
"create": "Criar de todo modo",
|
||||||
"title": "Alguns livros não estão combinados"
|
"title": "Alguns livros não estão combinados"
|
||||||
},
|
},
|
||||||
|
|
@ -286,6 +318,14 @@
|
||||||
"tab_title": "Importação de Dados"
|
"tab_title": "Importação de Dados"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
"add_api_key": {
|
||||||
|
"button_confirm": "Gerar",
|
||||||
|
"context": "Chaves API podem ser usadas para autenticar no protocolo Kobo Sync.",
|
||||||
|
"dialog_title": "Gerar chave de API",
|
||||||
|
"field_comment": "Comentar",
|
||||||
|
"field_comment_hint": "Como a chave API será usada?",
|
||||||
|
"info_copy": "Tenha a certeza de que a chave API foi salva. Você não poderá vê-la novamente!"
|
||||||
|
},
|
||||||
"add_to_collection": {
|
"add_to_collection": {
|
||||||
"button_create": "Criar",
|
"button_create": "Criar",
|
||||||
"card_collection_subtitle": "Nenhuma série | 1 série | {count} série",
|
"card_collection_subtitle": "Nenhuma série | 1 série | {count} série",
|
||||||
|
|
@ -319,6 +359,12 @@
|
||||||
"filter": "Filtrar por número, título ou data de lançamento",
|
"filter": "Filtrar por número, título ou data de lançamento",
|
||||||
"title": "Selecionar livro"
|
"title": "Selecionar livro"
|
||||||
},
|
},
|
||||||
|
"delete_apikey": {
|
||||||
|
"button_confirm": "Excluir",
|
||||||
|
"confirm_delete": "Eu entendo, exclua a chave API \"{name}\"",
|
||||||
|
"dialog_title": "Deletar chave API",
|
||||||
|
"warning_html": "Quaisquer aplicativos ou scripts que utilizem esta chave API não poderão mais acessar a API Komga. Você não poderá desfazer esta ação."
|
||||||
|
},
|
||||||
"delete_book": {
|
"delete_book": {
|
||||||
"button_confirm": "Excluir",
|
"button_confirm": "Excluir",
|
||||||
"confirm_delete": "Sim, exclua o livro \"{name}\" e seus arquivos",
|
"confirm_delete": "Sim, exclua o livro \"{name}\" e seus arquivos",
|
||||||
|
|
@ -468,6 +514,9 @@
|
||||||
"tab_general": "Geral",
|
"tab_general": "Geral",
|
||||||
"tab_poster": "Pôster"
|
"tab_poster": "Pôster"
|
||||||
},
|
},
|
||||||
|
"edit_recommended": {
|
||||||
|
"button_confirm": "Salvar mudanças"
|
||||||
|
},
|
||||||
"edit_series": {
|
"edit_series": {
|
||||||
"button_cancel": "Cancelar",
|
"button_cancel": "Cancelar",
|
||||||
"button_confirm": "Salvar mudanças",
|
"button_confirm": "Salvar mudanças",
|
||||||
|
|
@ -536,6 +585,9 @@
|
||||||
},
|
},
|
||||||
"title": "Nome do Arquivo de Destino"
|
"title": "Nome do Arquivo de Destino"
|
||||||
},
|
},
|
||||||
|
"force_kobo_sync": {
|
||||||
|
"dialog_title": "Forçar sincronização com Kobo"
|
||||||
|
},
|
||||||
"password_change": {
|
"password_change": {
|
||||||
"button_cancel": "Cancelar",
|
"button_cancel": "Cancelar",
|
||||||
"button_confirm": "Mudar senha",
|
"button_confirm": "Mudar senha",
|
||||||
|
|
@ -603,6 +655,9 @@
|
||||||
"HARDLINK": "Hardlink/Copiar arquivos",
|
"HARDLINK": "Hardlink/Copiar arquivos",
|
||||||
"MOVE": "Mover Arquivos"
|
"MOVE": "Mover Arquivos"
|
||||||
},
|
},
|
||||||
|
"media_profile": {
|
||||||
|
"PDF": "PDF"
|
||||||
|
},
|
||||||
"media_status": {
|
"media_status": {
|
||||||
"ERROR": "Erro",
|
"ERROR": "Erro",
|
||||||
"OUTDATED": "Desatualizado",
|
"OUTDATED": "Desatualizado",
|
||||||
|
|
@ -629,6 +684,14 @@
|
||||||
"ONGOING": "Em andamento"
|
"ONGOING": "Em andamento"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"epubreader": {
|
||||||
|
"settings": {
|
||||||
|
"page_margins": "Margem de Páginas"
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"settings": "Configurações"
|
||||||
|
}
|
||||||
|
},
|
||||||
"error_codes": {
|
"error_codes": {
|
||||||
"ERR_1000": "O arquivo não pôde ser acessado durante a análise",
|
"ERR_1000": "O arquivo não pôde ser acessado durante a análise",
|
||||||
"ERR_1001": "O tipo de mídia não é compatível",
|
"ERR_1001": "O tipo de mídia não é compatível",
|
||||||
|
|
@ -660,6 +723,7 @@
|
||||||
"in_progress": "Em progresso",
|
"in_progress": "Em progresso",
|
||||||
"language": "idioma",
|
"language": "idioma",
|
||||||
"library": "biblioteca",
|
"library": "biblioteca",
|
||||||
|
"oneshot": "One-shot",
|
||||||
"publisher": "editora",
|
"publisher": "editora",
|
||||||
"read": "Lidos",
|
"read": "Lidos",
|
||||||
"release_date": "data de lançamento",
|
"release_date": "data de lançamento",
|
||||||
|
|
@ -673,7 +737,8 @@
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"header": {
|
"header": {
|
||||||
"book": "Livro"
|
"book": "Livro",
|
||||||
|
"details": "Detalhes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
|
|
@ -795,6 +860,9 @@
|
||||||
"tooltip_too_big": "Arquivo muito grande!",
|
"tooltip_too_big": "Arquivo muito grande!",
|
||||||
"tooltip_user_uploaded": "Enviado pelo usuário"
|
"tooltip_user_uploaded": "Enviado pelo usuário"
|
||||||
},
|
},
|
||||||
|
"ui_settings": {
|
||||||
|
"general": "Geral"
|
||||||
|
},
|
||||||
"user_roles": {
|
"user_roles": {
|
||||||
"ADMIN": "Administrador",
|
"ADMIN": "Administrador",
|
||||||
"FILE_DOWNLOAD": "Baixar arquivos",
|
"FILE_DOWNLOAD": "Baixar arquivos",
|
||||||
|
|
@ -802,6 +870,7 @@
|
||||||
"USER": "Usuário"
|
"USER": "Usuário"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
|
"api_keys": "Chaves API",
|
||||||
"authentication_activity": "Atividade de Autenticação",
|
"authentication_activity": "Atividade de Autenticação",
|
||||||
"users": "Usuários"
|
"users": "Usuários"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
"pageText": "{0}-{1} из {2}"
|
"pageText": "{0}-{1} из {2}"
|
||||||
},
|
},
|
||||||
"dataIterator": {
|
"dataIterator": {
|
||||||
"loadingText": "Загрузка объектов...",
|
"loadingText": "Загрузка элементов...",
|
||||||
"noResultsText": "Подходящих записей не найдено"
|
"noResultsText": "Совпадений не найдено"
|
||||||
},
|
},
|
||||||
"dataTable": {
|
"dataTable": {
|
||||||
"itemsPerPageText": "Строк на странице:",
|
"itemsPerPageText": "Строк на странице:",
|
||||||
|
|
@ -15,30 +15,33 @@
|
||||||
"counter": "Файлов: {0}",
|
"counter": "Файлов: {0}",
|
||||||
"counterSize": "Файлов: {0} (всего {1})"
|
"counterSize": "Файлов: {0} (всего {1})"
|
||||||
},
|
},
|
||||||
"noDataText": "Отсутствуют данные"
|
"noDataText": "Данные отсутствуют"
|
||||||
},
|
},
|
||||||
"account_settings": {
|
"account_settings": {
|
||||||
"account_settings": "Настройки Аккаунта",
|
"account_settings": "Настройки аккаунта",
|
||||||
"api_key": {
|
"api_key": {
|
||||||
"created_date": "Дата создания: {date}",
|
"created_date": "Дата создания: {date}",
|
||||||
"generate_api_key": "Сгенерировать API ключ",
|
"force_kobo_sync": "Принудительная синхронизация с Kobo",
|
||||||
|
"generate_api_key": "Сгенерировать ключ API",
|
||||||
"no_keys": "Ни одного ключа API еще не создано"
|
"no_keys": "Ни одного ключа API еще не создано"
|
||||||
},
|
},
|
||||||
"change_password": "изменить пароль"
|
"change_password": "изменить пароль",
|
||||||
|
"details": "Подробности",
|
||||||
|
"my_account": "Мой аккаунт"
|
||||||
},
|
},
|
||||||
"announcements": {
|
"announcements": {
|
||||||
"mark_all_read": "Пометить всё как прочитанное",
|
"mark_all_read": "Отметить всё как прочитанное",
|
||||||
"mark_read": "Пометить как прочитанное",
|
"mark_read": "Отметить как прочитанное",
|
||||||
"tab_title": "Объявления"
|
"tab_title": "Объявления"
|
||||||
},
|
},
|
||||||
"authentication_activity": {
|
"authentication_activity": {
|
||||||
"api_key": "API Ключ",
|
"api_key": "API-ключ",
|
||||||
"datetime": "Дата / Время",
|
"datetime": "Дата/Время",
|
||||||
"email": "Эл. почта",
|
"email": "Эл. почта",
|
||||||
"error": "Ошибка",
|
"error": "Ошибка",
|
||||||
"ip": "IP-адрес",
|
"ip": "IP-адрес",
|
||||||
"source": "Источник",
|
"source": "Источник",
|
||||||
"success": "Статус",
|
"success": "Успех",
|
||||||
"user_agent": "User Agent"
|
"user_agent": "User Agent"
|
||||||
},
|
},
|
||||||
"author_roles": {
|
"author_roles": {
|
||||||
|
|
@ -54,18 +57,18 @@
|
||||||
"book_card": {
|
"book_card": {
|
||||||
"error": "Ошибка",
|
"error": "Ошибка",
|
||||||
"no_release_date": "Дата релиза отсутствует",
|
"no_release_date": "Дата релиза отсутствует",
|
||||||
"unknown": "Необходимо проанализировать",
|
"unknown": "Подлежит анализу",
|
||||||
"unread": "Не прочитано",
|
"unread": "Не прочитано",
|
||||||
"unsupported": "Неподдерживаемый"
|
"unsupported": "Не поддерживается"
|
||||||
},
|
},
|
||||||
"book_import": {
|
"book_import": {
|
||||||
"button_browse": "Обзор",
|
"button_browse": "Обзор",
|
||||||
"button_import": "Импортировать",
|
"button_import": "Импорт",
|
||||||
"button_scan": "Сканировать",
|
"button_scan": "Сканировать",
|
||||||
"button_select_series": "Выберите Серию",
|
"button_select_series": "Выберите серию",
|
||||||
"field_import_path": "Импортировать из каталога",
|
"field_import_path": "Импортировать из каталога",
|
||||||
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие Серии, в этом случае Komga переместит или скопирует файлы в каталог выбранной Серии.",
|
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие серии; в этом случае Komga переместит или скопирует файлы в каталог выбранной серии.",
|
||||||
"info_part2": "Если вы выберете номер для книги и книга с таким номером уже существует, то вы сможете сравнить 2 книги. Если вы решите импортировать книгу, Komga обновит существующую книгу, эффективно заменив старый файл новым.",
|
"info_part2": "Если вы укажете номер для книги, и книга с таким номером уже существует, вы сможете сравнить оба варианта. Если вы решите импортировать книгу, Komga обновит существующий вариант, заменив старый файл новым.",
|
||||||
"no_files_found": "Файлы не найдены",
|
"no_files_found": "Файлы не найдены",
|
||||||
"notification": {
|
"notification": {
|
||||||
"go_to_book": "Перейти к книге",
|
"go_to_book": "Перейти к книге",
|
||||||
|
|
@ -74,9 +77,9 @@
|
||||||
"source_file": "Исходный файл: {file}"
|
"source_file": "Исходный файл: {file}"
|
||||||
},
|
},
|
||||||
"row": {
|
"row": {
|
||||||
"error_analyze_first": "Книгу нужно сначала проанализировать",
|
"error_analyze_first": "Книга нуждается в предварительном анализе",
|
||||||
"error_choose_series": "Выберите серию",
|
"error_choose_series": "Выберите серию",
|
||||||
"error_only_import_no_errors": "Можно импортировать только книги без ошибок",
|
"error_only_import_no_errors": "Можно импортировать только книги без наличия ошибок",
|
||||||
"warning_upgrade": "Существующая книга будет обновлена"
|
"warning_upgrade": "Существующая книга будет обновлена"
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
|
|
@ -90,10 +93,11 @@
|
||||||
},
|
},
|
||||||
"bookreader": {
|
"bookreader": {
|
||||||
"beginning_of_book": "Вы находитесь в начале книги.",
|
"beginning_of_book": "Вы находитесь в начале книги.",
|
||||||
"changing_reading_direction": "Изменение Направления Чтения на",
|
"changing_reading_direction": "Изменение направления чтения на",
|
||||||
"cycling_page_layout": "Переключить Формат Страниц",
|
"cycling_page_layout": "Переключение макета страницы",
|
||||||
"cycling_scale": "Переключить Масштабирование",
|
"cycling_page_margin": "Переключение полей страницы",
|
||||||
"cycling_side_padding": "Переключить Боковой Отступ",
|
"cycling_scale": "Масштабирование",
|
||||||
|
"cycling_side_padding": "Переключение боковых отступов",
|
||||||
"download_current_page": "Скачать текущую страницу",
|
"download_current_page": "Скачать текущую страницу",
|
||||||
"end_of_book": "Вы достигли конца книги.",
|
"end_of_book": "Вы достигли конца книги.",
|
||||||
"from_series_metadata": "из метаданных серии",
|
"from_series_metadata": "из метаданных серии",
|
||||||
|
|
@ -104,8 +108,8 @@
|
||||||
"notification_poster_set_readlist": "Текущая страница теперь используется в качестве постера списка чтения.",
|
"notification_poster_set_readlist": "Текущая страница теперь используется в качестве постера списка чтения.",
|
||||||
"notification_poster_set_series": "Текущая страница теперь используется в качестве постера серии.",
|
"notification_poster_set_series": "Текущая страница теперь используется в качестве постера серии.",
|
||||||
"paged_reader_layout": {
|
"paged_reader_layout": {
|
||||||
"double": "Двойные страницы",
|
"double": "Две страницы",
|
||||||
"double_no_cover": "Двойные страницы (без обложки)",
|
"double_no_cover": "Две страницы (без обложки)",
|
||||||
"single": "Одна страница"
|
"single": "Одна страница"
|
||||||
},
|
},
|
||||||
"reader_settings": "Настройки Ридера",
|
"reader_settings": "Настройки Ридера",
|
||||||
|
|
@ -114,16 +118,16 @@
|
||||||
"continuous_width": "По ширине",
|
"continuous_width": "По ширине",
|
||||||
"height": "По высоте",
|
"height": "По высоте",
|
||||||
"original": "Исходное",
|
"original": "Исходное",
|
||||||
"screen": "По экрану",
|
"screen": "По размеру экрана",
|
||||||
"width": "По ширине",
|
"width": "По ширине",
|
||||||
"width_shrink_only": "По ширине (с отступами)"
|
"width_shrink_only": "По ширине (с отступами)"
|
||||||
},
|
},
|
||||||
"set_current_page_as_book_poster": "Установить страницу в качестве постера для книги",
|
"set_current_page_as_book_poster": "Установить страницу в качестве обложки для книги",
|
||||||
"set_current_page_as_readlist_poster": "Установить страницу в качестве постера для списка чтения",
|
"set_current_page_as_readlist_poster": "Установить страницу в качестве обложки для списка чтения",
|
||||||
"set_current_page_as_series_poster": "Установить страницу в качестве постера для серии",
|
"set_current_page_as_series_poster": "Установить страницу в качестве обложки для серии",
|
||||||
"settings": {
|
"settings": {
|
||||||
"always_fullscreen": "Всегда в полный экран",
|
"always_fullscreen": "Всегда полноэкранный режим",
|
||||||
"animate_page_transitions": "Анимировать переходы страниц",
|
"animate_page_transitions": "Анимировать переходы между страницами",
|
||||||
"background_color": "Цвет фона",
|
"background_color": "Цвет фона",
|
||||||
"background_colors": {
|
"background_colors": {
|
||||||
"black": "Чёрный",
|
"black": "Чёрный",
|
||||||
|
|
@ -134,54 +138,60 @@
|
||||||
"general": "Общее",
|
"general": "Общее",
|
||||||
"gestures": "Жесты",
|
"gestures": "Жесты",
|
||||||
"page_layout": "Формат страницы",
|
"page_layout": "Формат страницы",
|
||||||
"paged": "Настройки Отображения Страниц",
|
"page_margin": "Поля страницы",
|
||||||
|
"paged": "Настройки отображения страниц",
|
||||||
"reading_mode": "Режим чтения",
|
"reading_mode": "Режим чтения",
|
||||||
"scale_type": "Масштабирование",
|
"scale_type": "Масштабирование",
|
||||||
"side_padding": "Боковой отступ",
|
"side_padding": "Боковые отступы",
|
||||||
"side_padding_none": "Нет",
|
"side_padding_none": "Нет",
|
||||||
"webtoon": "Параметры Режима Webtoon"
|
"webtoon": "Настройки режима цифрового комикса"
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"close": "Закрыть",
|
"close": "Закрыть",
|
||||||
"cycle_page_layout": "Переключить формат страниц",
|
"cycle_page_layout": "Переключить макет страницы",
|
||||||
|
"cycle_page_margin": "Переключить поля страницы",
|
||||||
"cycle_scale": "Переключить масштаб",
|
"cycle_scale": "Переключить масштаб",
|
||||||
"cycle_side_padding": "Переключить боковой отступ",
|
"cycle_side_padding": "Переключить боковые отступы",
|
||||||
"first_page": "Первая страница",
|
"first_page": "Первая страница",
|
||||||
"fullscreen": "Войти/выйти из полноэкранного режима",
|
"fullscreen": "Войти/выйти из полноэкранного режима",
|
||||||
"last_page": "Последняя страница",
|
"last_page": "Последняя страница",
|
||||||
"left_to_right": "Слева Направо",
|
"left_to_right": "Слева направо",
|
||||||
"menus": "Меню",
|
"menus": "Меню",
|
||||||
"next_page": "Следующая страница",
|
"next_page": "Следующая страница",
|
||||||
"previous_page": "Предыдущая страница",
|
"previous_page": "Предыдущая страница",
|
||||||
"reader_navigation": "Навигация",
|
"reader_navigation": "Навигация",
|
||||||
"right_to_left": "Справа Налево",
|
"right_to_left": "Справа налево",
|
||||||
"settings": "Настройки",
|
"settings": "Настройки",
|
||||||
"show_hide_help": "Показать/скрыть помощь",
|
"show_hide_help": "Показать/скрыть помощь",
|
||||||
"show_hide_settings": "Показать/скрыть меню настроек",
|
"show_hide_settings": "Показать/скрыть меню настроек",
|
||||||
"show_hide_thumbnails": "Показать/скрыть просмотр эскизов",
|
"show_hide_thumbnails": "Показать/скрыть обозреватель миниатюр",
|
||||||
"show_hide_toolbars": "Показать/скрыть панели инструментов",
|
"show_hide_toolbars": "Показать/скрыть панели инструментов",
|
||||||
"vertical": "Вертикально",
|
"vertical": "Вертикально",
|
||||||
"webtoon": "Webtoon"
|
"webtoon": "Цифровой комикс"
|
||||||
},
|
},
|
||||||
"tooltip_incognito": "Прогресс чтения не будет сохранен"
|
"tooltip_incognito": "Прогресс чтения не будет сохранен"
|
||||||
},
|
},
|
||||||
"browse_book": {
|
"browse_book": {
|
||||||
"comment": "КОММЕНТАРИЙ",
|
"comment": "КОММЕНТАРИЙ",
|
||||||
|
"date_created": "СОЗДАНО",
|
||||||
|
"date_modified": "ПОСЛЕДНЕЕ ИЗМЕНЕНИЕ",
|
||||||
"download_file": "Скачать файл",
|
"download_file": "Скачать файл",
|
||||||
"file": "ФАЙЛ",
|
"file": "ФАЙЛ",
|
||||||
"format": "ФОРМАТ",
|
"format": "ФОРМАТ",
|
||||||
"isbn": "ISBN",
|
"isbn": "ISBN",
|
||||||
"links": "ССЫЛКИ",
|
"links": "ССЫЛКИ",
|
||||||
"navigation_within_readlist": "Навигация в пределах списка чтения: {name}",
|
"navigation_within_readlist": "Навигация внутри списка чтения: {name}",
|
||||||
"outdated_tooltip": "Файл этой книги изменен, книгу необходимо повторно проанализировать",
|
"outdated_tooltip": "Файл этой книги изменился, книгу необходимо повторно проанализировать",
|
||||||
"read_book": "Читать книгу",
|
"read_book": "Читать книгу",
|
||||||
"read_incognito": "Читать инкогнито",
|
"read_incognito": "Читать инкогнито",
|
||||||
|
"remove_from_collection": "Удалить книгу из коллекции",
|
||||||
|
"remove_from_readlist": "Удалить книгу из списка чтения",
|
||||||
"size": "РАЗМЕР"
|
"size": "РАЗМЕР"
|
||||||
},
|
},
|
||||||
"browse_collection": {
|
"browse_collection": {
|
||||||
"edit_collection": "Редактировать коллекцию",
|
"edit_collection": "Редактировать коллекцию",
|
||||||
"edit_elements": "Редактировать элементы",
|
"edit_elements": "Редактировать элементы",
|
||||||
"manual_ordering": "ручной порядок"
|
"manual_ordering": "ручная сортировка"
|
||||||
},
|
},
|
||||||
"browse_readlist": {
|
"browse_readlist": {
|
||||||
"edit_elements": "Редактировать элементы",
|
"edit_elements": "Редактировать элементы",
|
||||||
|
|
@ -189,17 +199,19 @@
|
||||||
"manual_ordering": "ручная сортировка"
|
"manual_ordering": "ручная сортировка"
|
||||||
},
|
},
|
||||||
"browse_series": {
|
"browse_series": {
|
||||||
"earliest_year_from_release_dates": "Это самая ранняя дата выпуска из всех книг в этой серии",
|
"earliest_year_from_release_dates": "Это самый ранний год из дат выхода всех книг серии",
|
||||||
"series_no_summary": "У серии нет описания, поэтому мы подобрали его для вас!",
|
"remove_from_collection": "Удалить серию из коллекции",
|
||||||
|
"series_no_summary": "У этой серии нет описания, поэтому мы подобрали его для вас!",
|
||||||
"summary_from_book": "Краткое описание из книги {number}:"
|
"summary_from_book": "Краткое описание из книги {number}:"
|
||||||
},
|
},
|
||||||
"collections_expansion_panel": {
|
"collections_expansion_panel": {
|
||||||
"manage_collection": "Управлять коллекцией",
|
"manage_collection": "Управление коллекцией",
|
||||||
"title": "Коллекция {name}"
|
"title": "Коллекция {name}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"age": "Возраст",
|
"age": "Возраст",
|
||||||
"all_libraries": "Все Библиотеки",
|
"all_libraries": "Все библиотеки",
|
||||||
|
"any_of": "Любой из",
|
||||||
"book": "Книга",
|
"book": "Книга",
|
||||||
"books": "Книги",
|
"books": "Книги",
|
||||||
"books_n": "Книг нет | 1 книга | {count} книг",
|
"books_n": "Книг нет | 1 книга | {count} книг",
|
||||||
|
|
@ -212,14 +224,16 @@
|
||||||
"copied": "Скопировано!",
|
"copied": "Скопировано!",
|
||||||
"create": "Создать",
|
"create": "Создать",
|
||||||
"delete": "Удалить",
|
"delete": "Удалить",
|
||||||
"dimension": "шир.: {width} выс.: {height}",
|
"dimension": "шир.: {width}, выс.: {height}",
|
||||||
"discard": "Отмена",
|
"discard": "Отмена",
|
||||||
"disk_space": "Дисковое пространство",
|
"disk_space": "Дисковое пространство",
|
||||||
"dismiss": "Отклонить",
|
"dismiss": "Отклонить",
|
||||||
"download": "Скачать",
|
"download": "Скачать",
|
||||||
"drag_drop": "перетащить",
|
"drag_drop": "перетащить",
|
||||||
|
"duplicate": "Дублировать",
|
||||||
"email": "Эл. почта",
|
"email": "Эл. почта",
|
||||||
"epub": "Epub",
|
"epub": "Epub",
|
||||||
|
"error": "Ошибка",
|
||||||
"filename": "Имя файла",
|
"filename": "Имя файла",
|
||||||
"filter_no_matches": "Нет совпадений по заданному фильтру",
|
"filter_no_matches": "Нет совпадений по заданному фильтру",
|
||||||
"genre": "Жанр",
|
"genre": "Жанр",
|
||||||
|
|
@ -227,12 +241,16 @@
|
||||||
"go_to_library": "Вернуться к библиотеке",
|
"go_to_library": "Вернуться к библиотеке",
|
||||||
"go_to_readlist": "Перейти к списку чтения",
|
"go_to_readlist": "Перейти к списку чтения",
|
||||||
"go_to_series": "Перейти к серии",
|
"go_to_series": "Перейти к серии",
|
||||||
|
"i_understand": "Я понимаю",
|
||||||
"library": "Библиотека",
|
"library": "Библиотека",
|
||||||
"locale_name": "Русский",
|
"locale_name": "Русский",
|
||||||
"locale_rtl": "false",
|
"locale_rtl": "false",
|
||||||
"lock_all": "Заблокировать все",
|
"lock_all": "Заблокировать все",
|
||||||
|
"media": "Медиа",
|
||||||
|
"more": "Ещё",
|
||||||
"n_selected": "{count} выбрано",
|
"n_selected": "{count} выбрано",
|
||||||
"nothing_to_show": "Нет данных для отображения",
|
"nothing_to_show": "Нет данных для отображения",
|
||||||
|
"ok": "OK",
|
||||||
"outdated": "Устарело",
|
"outdated": "Устарело",
|
||||||
"page": "Страница",
|
"page": "Страница",
|
||||||
"page_number": "Номер страницы",
|
"page_number": "Номер страницы",
|
||||||
|
|
@ -242,17 +260,20 @@
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
"pdf": "PDF",
|
"pdf": "PDF",
|
||||||
"pending_tasks": "Нет незавершенных задач | 1 незавершенная задача | {count} незавершенных задач",
|
"pending_tasks": "Нет незавершенных задач | 1 незавершенная задача | {count} незавершенных задач",
|
||||||
|
"pinned_libraries": "Закреплённые библиотеки",
|
||||||
"publisher": "Издатель",
|
"publisher": "Издатель",
|
||||||
"read": "Читать",
|
"read": "Читать",
|
||||||
"read_on": "Читать {date}",
|
"read_on": "Прочитано {date}",
|
||||||
"readlist": "Список чтения",
|
"readlist": "Список чтения",
|
||||||
"readlists": "Списки чтения",
|
"readlists": "Списки чтения",
|
||||||
"remember-me": "Запомнить",
|
"remember-me": "Запомнить меня",
|
||||||
"required": "Необходимо",
|
"reorder": "Изменить порядок",
|
||||||
|
"required": "Обязательно",
|
||||||
"reset_filters": "Сбросить фильтры",
|
"reset_filters": "Сбросить фильтры",
|
||||||
"roles": "Роли",
|
"roles": "Роли",
|
||||||
"save_changes": "Сохранить изменения",
|
"save_changes": "Сохранить изменения",
|
||||||
"series": "Серии",
|
"series": "Серии",
|
||||||
|
"settings": "Настройки",
|
||||||
"tags": "Теги",
|
"tags": "Теги",
|
||||||
"unavailable": "Недоступно",
|
"unavailable": "Недоступно",
|
||||||
"unlock_all": "Разблокировать все",
|
"unlock_all": "Разблокировать все",
|
||||||
|
|
|
||||||
1092
komga-webui/src/locales/sk.json
Normal file
1092
komga-webui/src/locales/sk.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -97,7 +97,7 @@
|
||||||
"cycling_page_layout": "Шаблон сторінки",
|
"cycling_page_layout": "Шаблон сторінки",
|
||||||
"cycling_page_margin": "Відступи",
|
"cycling_page_margin": "Відступи",
|
||||||
"cycling_scale": "Масштабування",
|
"cycling_scale": "Масштабування",
|
||||||
"cycling_side_padding": "Cycling Side Padding",
|
"cycling_side_padding": "Бічні накладки для велосипедистів",
|
||||||
"download_current_page": "Завантажити поточку сторінку",
|
"download_current_page": "Завантажити поточку сторінку",
|
||||||
"end_of_book": "Ви дійшли до кінця книги.",
|
"end_of_book": "Ви дійшли до кінця книги.",
|
||||||
"from_series_metadata": "з метаданих серії",
|
"from_series_metadata": "з метаданих серії",
|
||||||
|
|
@ -139,6 +139,7 @@
|
||||||
"gestures": "Жести",
|
"gestures": "Жести",
|
||||||
"page_layout": "Шаблон сторінки",
|
"page_layout": "Шаблон сторінки",
|
||||||
"page_margin": "Відступ сторінки",
|
"page_margin": "Відступ сторінки",
|
||||||
|
"paged": "Параметри зчитування з розбивкою на сторінки",
|
||||||
"reading_mode": "Режим читання",
|
"reading_mode": "Режим читання",
|
||||||
"scale_type": "Тип масштабування",
|
"scale_type": "Тип масштабування",
|
||||||
"side_padding": "Бокові відступи",
|
"side_padding": "Бокові відступи",
|
||||||
|
|
@ -147,6 +148,10 @@
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"close": "Закрити",
|
"close": "Закрити",
|
||||||
|
"cycle_page_layout": "Перемикання макета сторінки",
|
||||||
|
"cycle_page_margin": "Перемикання полів сторінки",
|
||||||
|
"cycle_scale": "Шкала циклу",
|
||||||
|
"cycle_side_padding": "Бічна підкладка для велосипеда",
|
||||||
"first_page": "Перша сторінка",
|
"first_page": "Перша сторінка",
|
||||||
"fullscreen": "Увімкнути/вимкнути повноекранний режим",
|
"fullscreen": "Увімкнути/вимкнути повноекранний режим",
|
||||||
"last_page": "Остання сторінка",
|
"last_page": "Остання сторінка",
|
||||||
|
|
@ -174,9 +179,914 @@
|
||||||
"file": "ФАЙЛ",
|
"file": "ФАЙЛ",
|
||||||
"format": "ФОРМАТ",
|
"format": "ФОРМАТ",
|
||||||
"isbn": "ISBN",
|
"isbn": "ISBN",
|
||||||
"links": "ПОСИЛАННЯ"
|
"links": "ПОСИЛАННЯ",
|
||||||
|
"navigation_within_readlist": "Навігація у списку для читання: {name}",
|
||||||
|
"outdated_tooltip": "Файл цієї книги змінився, цю книгу потрібно проаналізувати повторно",
|
||||||
|
"read_book": "Читати книгу",
|
||||||
|
"read_incognito": "Читати інкогніто",
|
||||||
|
"remove_from_collection": "Вилучити книгу з колекції",
|
||||||
|
"remove_from_readlist": "Вилучити книгу зі списку прочитаних",
|
||||||
|
"size": "РОЗМІР"
|
||||||
|
},
|
||||||
|
"browse_collection": {
|
||||||
|
"edit_collection": "Редагувати колекцію",
|
||||||
|
"edit_elements": "Редагувати елементи",
|
||||||
|
"manual_ordering": "ручне замовлення"
|
||||||
|
},
|
||||||
|
"browse_readlist": {
|
||||||
|
"edit_elements": "Редагувати елементи",
|
||||||
|
"edit_readlist": "Редагувати список прочитаних",
|
||||||
|
"manual_ordering": "ручне замовлення"
|
||||||
|
},
|
||||||
|
"browse_series": {
|
||||||
|
"earliest_year_from_release_dates": "Це найдавніший рік з дат виходу всіх книг серії",
|
||||||
|
"remove_from_collection": "Вилучити серію з колекції",
|
||||||
|
"series_no_summary": "У цієї серії немає короткого опису, тому ми вибрали його для вас!",
|
||||||
|
"summary_from_book": "Короткий зміст з книги {number}:"
|
||||||
|
},
|
||||||
|
"collections_expansion_panel": {
|
||||||
|
"manage_collection": "Керування колекцією",
|
||||||
|
"title": "колекція {name}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"locale_name": "Українська"
|
"age": "Вік",
|
||||||
|
"all_libraries": "Усі бібліотеки",
|
||||||
|
"all_of": "Усі з",
|
||||||
|
"any_of": "Будь-який з",
|
||||||
|
"book": "Книга",
|
||||||
|
"books": "Книги",
|
||||||
|
"books_n": "Немає книги | 1 книга | {count} книг",
|
||||||
|
"books_total": "{count} / {total} книг",
|
||||||
|
"cancel": "Скасувати",
|
||||||
|
"cbx": "Архів коміксів",
|
||||||
|
"choose_image": "Виберіть зображення",
|
||||||
|
"close": "Закрити",
|
||||||
|
"collections": "Колекції",
|
||||||
|
"copied": "Скопійовано!",
|
||||||
|
"create": "Створити",
|
||||||
|
"delete": "Видалити",
|
||||||
|
"dimension": "У: {width}, г: {height}",
|
||||||
|
"discard": "Відкинути",
|
||||||
|
"disk_space": "Місце на диску",
|
||||||
|
"dismiss": "Відхилити",
|
||||||
|
"download": "Завантажити",
|
||||||
|
"drag_drop": "перетягування",
|
||||||
|
"duplicate": "Дублікат",
|
||||||
|
"email": "Електронна пошта",
|
||||||
|
"epub": "Електронна книга",
|
||||||
|
"error": "Помилка",
|
||||||
|
"filename": "Ім'я файлу",
|
||||||
|
"filter_no_matches": "Активний фільтр не має збігів",
|
||||||
|
"genre": "Жанр",
|
||||||
|
"go_to_collection": "Перейти до колекції",
|
||||||
|
"go_to_library": "Іди до бібліотеки",
|
||||||
|
"go_to_readlist": "Перейти до списку прочитання",
|
||||||
|
"go_to_series": "Перейти до серії",
|
||||||
|
"i_understand": "Я розумію",
|
||||||
|
"library": "Бібліотека",
|
||||||
|
"locale_name": "Українська",
|
||||||
|
"locale_rtl": "false",
|
||||||
|
"lock_all": "Заблокувати все",
|
||||||
|
"media": "Медіа",
|
||||||
|
"more": "Більше",
|
||||||
|
"n_selected": "Вибрано {count}",
|
||||||
|
"nothing_to_show": "Нічого показати",
|
||||||
|
"ok": "Гаразд",
|
||||||
|
"oneshot": "Одноразовий",
|
||||||
|
"outdated": "Застарілий",
|
||||||
|
"page": "Сторінка",
|
||||||
|
"page_number": "Номер сторінки",
|
||||||
|
"pages": "сторінки",
|
||||||
|
"pages_left": "Не залишилося сторінок | Залишилася 1 сторінка | Залишилося {count} сторінок",
|
||||||
|
"pages_n": "Немає сторінок | 1 сторінка | {count} сторінок",
|
||||||
|
"password": "Пароль",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pending_tasks": "Немає завдань, що очікують на розгляд | 1 завдання, що очікує на розгляд | {count} завдань, що очікують на розгляд",
|
||||||
|
"pinned_libraries": "Закріплені бібліотеки",
|
||||||
|
"publisher": "Видавець",
|
||||||
|
"read": "Читати",
|
||||||
|
"read_on": "Читайте далі {date}",
|
||||||
|
"readlist": "Список прочитаних",
|
||||||
|
"readlists": "Списки для читання",
|
||||||
|
"remember-me": "Запам'ятай мене",
|
||||||
|
"reorder": "Знову замовити",
|
||||||
|
"required": "Обов'язково",
|
||||||
|
"reset_filters": "Скинути фільтри",
|
||||||
|
"roles": "Ролі",
|
||||||
|
"save_changes": "Зберегти зміни",
|
||||||
|
"series": "Серія | Серія",
|
||||||
|
"settings": "Налаштування",
|
||||||
|
"sidecars": "Коляски",
|
||||||
|
"tags": "Теги",
|
||||||
|
"ui": "Інтерфейс користувача",
|
||||||
|
"unavailable": "Недоступно",
|
||||||
|
"unlock_all": "Розблокувати все",
|
||||||
|
"url": "URL",
|
||||||
|
"use_filter_panel_to_change_filter": "Використовуйте панель фільтрів, щоб змінити активний фільтр",
|
||||||
|
"year": "рік"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"keep_reading": "Продовжуйте читати",
|
||||||
|
"on_deck": "На палубі",
|
||||||
|
"recently_added_books": "Нещодавно додані книги",
|
||||||
|
"recently_added_series": "Нещодавно додані серії",
|
||||||
|
"recently_read_books": "Нещодавно прочитані книги",
|
||||||
|
"recently_released_books": "Нещодавно випущені книги",
|
||||||
|
"recently_updated_series": "Нещодавно оновлені серії"
|
||||||
|
},
|
||||||
|
"data_import": {
|
||||||
|
"book_number": "Номер книги: {name}",
|
||||||
|
"book_series": "Серія: {name}",
|
||||||
|
"button_import": "Імпорт",
|
||||||
|
"button_match": "Матч",
|
||||||
|
"comicrack_preambule_html": "Ви можете імпортувати існуючі списки читання ComicRack у форматі <code>.cbl</code>.<br>Komga спробує зіставити надану серію та номер книги із серіями та книгами у ваших бібліотеках.",
|
||||||
|
"dialog_confirmation": {
|
||||||
|
"body": "{unmatched} / {total} книг не мають збігів",
|
||||||
|
"body2": "{duplicates} / {total} книг дублюються",
|
||||||
|
"create": "Створити все одно",
|
||||||
|
"title": "Деякі книги не збігаються"
|
||||||
|
},
|
||||||
|
"field_file_label": "Список для читання ComicRack (.cbl)",
|
||||||
|
"field_files_label": "Списки для читання ComicRack (.cbl)",
|
||||||
|
"import_read_lists": "Імпорт списків прочитаного",
|
||||||
|
"imported_as": "Імпортовано як {name}",
|
||||||
|
"readlist_created": "Список для читання створено: {name}",
|
||||||
|
"requested_number": "Запитаний номер",
|
||||||
|
"requested_series": "Запитана серія",
|
||||||
|
"results_preambule": "Результат імпорту показано нижче. Ви також можете перевірити незбігані книги для кожного наданого файлу.",
|
||||||
|
"size_limit": "Розмір має бути меншим за {size} МБ",
|
||||||
|
"tab_title": "Імпорт даних"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"add_api_key": {
|
||||||
|
"button_confirm": "Згенерувати",
|
||||||
|
"context": "Ключі API можна використовувати для автентифікації через протокол Kobo Sync.",
|
||||||
|
"dialog_title": "Згенерувати новий ключ API",
|
||||||
|
"field_comment": "Коментар",
|
||||||
|
"field_comment_hint": "Для чого цей ключ API?",
|
||||||
|
"info_copy": "Обов’язково скопіюйте свій ключ API зараз. Ви більше його не побачите!"
|
||||||
|
},
|
||||||
|
"add_to_collection": {
|
||||||
|
"button_create": "Створити",
|
||||||
|
"card_collection_subtitle": "Без серій | 1 серія | {count} серій",
|
||||||
|
"dialog_title": "Додати до колекції",
|
||||||
|
"field_search_create": "Пошук або створення колекції",
|
||||||
|
"field_search_create_error": "Колекція з такою назвою вже існує",
|
||||||
|
"label_no_matching_collection": "Немає відповідної колекції"
|
||||||
|
},
|
||||||
|
"add_to_readlist": {
|
||||||
|
"button_create": "Створити",
|
||||||
|
"card_readlist_subtitle": "Немає книги | 1 книга | {count} книг",
|
||||||
|
"dialog_title": "Додати до списку прочитання",
|
||||||
|
"field_search_create": "Пошук або створення списку для читання",
|
||||||
|
"field_search_create_error": "Список для читання з такою назвою вже існує",
|
||||||
|
"label_no_matching_readlist": "Немає відповідного списку для читання"
|
||||||
|
},
|
||||||
|
"add_user": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Додати",
|
||||||
|
"dialog_title": "Додати користувача",
|
||||||
|
"field_email": "Електронна пошта",
|
||||||
|
"field_email_error": "Має бути дійсна адреса електронної пошти",
|
||||||
|
"field_password": "Пароль"
|
||||||
|
},
|
||||||
|
"analyze_library": {
|
||||||
|
"body": "Аналізує всі медіафайли в бібліотеці. Аналіз збирає інформацію про медіафайли. Залежно від розміру вашої бібліотеки, це може тривати довго.",
|
||||||
|
"button_confirm": "Аналіз",
|
||||||
|
"title": "Аналіз бібліотеки"
|
||||||
|
},
|
||||||
|
"book_picker": {
|
||||||
|
"filter": "Фільтрувати за номером книги, назвою або датою виходу",
|
||||||
|
"title": "Виберіть книгу"
|
||||||
|
},
|
||||||
|
"delete_apikey": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Я розумію, видаліть ключ API \"{name}\"",
|
||||||
|
"dialog_title": "Видалити ключ API",
|
||||||
|
"warning_html": "Будь-які програми чи скрипти, що використовують цей ключ API, більше не матимуть доступу до API Komga. Ви не можете скасувати цю дію."
|
||||||
|
},
|
||||||
|
"delete_book": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити книгу «{name}» та її файли",
|
||||||
|
"confirm_delete_multiple": "Так, видалити {count} книг та їхні файли",
|
||||||
|
"dialog_title": "Видалити книгу",
|
||||||
|
"dialog_title_multiple": "Видалити книги",
|
||||||
|
"warning_html": "Книгу <b>{name}</b> буде видалено з цього сервера разом зі збереженими медіафайлами. Цю дію <b>неможливо</b> скасувати. Продовжити?",
|
||||||
|
"warning_multiple_html": "{count} Книги будуть вилучені з цього сервера разом зі збереженими медіафайлами. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"delete_collection": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити колекцію \"{name}\"",
|
||||||
|
"confirm_delete_multiple": "Так, видалити {count} колекцій",
|
||||||
|
"dialog_title": "Видалити колекцію",
|
||||||
|
"dialog_title_multiple": "Видалити колекції",
|
||||||
|
"warning_html": "Колекцію <b>{name}</b> буде видалено з цього сервера. Ваші медіафайли залишаться в силі. Цю дію <b>неможливо</b> скасувати. Продовжити?",
|
||||||
|
"warning_multiple_html": "{count} Колекції будуть видалені з цього сервера. Ваші медіафайли залишаться в силі. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"delete_library": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити бібліотеку \"{name}\"",
|
||||||
|
"title": "Видалити бібліотеку",
|
||||||
|
"warning_html": "Бібліотеку <b>{name}</b> буде видалено з цього сервера. Ваші медіафайли залишаться в силі. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"delete_readlist": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити список прочитаного \"{name}\"",
|
||||||
|
"confirm_delete_multiple": "Так, видалити {count} списків прочитання",
|
||||||
|
"dialog_title": "Видалити список прочитаних",
|
||||||
|
"dialog_title_multiple": "Видалити списки прочитаного",
|
||||||
|
"warning_html": "Список для читання <b>{name}</b> буде видалено з цього сервера. Ваші медіафайли залишаться в силі. Цю дію <b>неможливо</b> скасувати. Продовжити?",
|
||||||
|
"warning_multiple_html": "{count} Списки прочитання будуть видалені з цього сервера. Ваші медіафайли залишаться в силі. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"delete_series": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити серію \"{name}\" та її файли",
|
||||||
|
"confirm_delete_multiple": "Так, видалити {count} серій та їхні файли",
|
||||||
|
"dialog_title": "Видалити серію",
|
||||||
|
"warning_html": "Серіал <b>{name}</b> буде видалено з цього сервера разом зі збереженими медіафайлами. Цю дію <b>неможливо</b> скасувати. Продовжити?",
|
||||||
|
"warning_multiple_html": "Серії ({count}) будуть видалені з цього сервера разом зі збереженими медіафайлами. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"delete_user": {
|
||||||
|
"button_confirm": "Видалити",
|
||||||
|
"confirm_delete": "Так, видалити користувача \"{name}\"",
|
||||||
|
"dialog_title": "Видалити користувача",
|
||||||
|
"warning_html": "Користувача <b>{name}</b> буде видалено з цього сервера. Цю дію <b>неможливо</b> скасувати. Продовжити?"
|
||||||
|
},
|
||||||
|
"edit_books": {
|
||||||
|
"add_author_role_error_duplicate": "Вже існує",
|
||||||
|
"authors_notice_multiple_edit": "Ви редагуєте авторів кількох книг. Це замінить існуючих авторів кожної книги.",
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"copy_from": "Копіювати з {field}",
|
||||||
|
"dialog_title_multiple": "Редагувати книгу {count} | Редагувати книги {count}",
|
||||||
|
"dialog_title_single": "Редагувати {book}",
|
||||||
|
"field_alternate_title": "Альтернативна назва",
|
||||||
|
"field_isbn": "ISBN",
|
||||||
|
"field_isbn_error": "Повинен бути дійсний ISBN 13",
|
||||||
|
"field_link_label": "Мітка",
|
||||||
|
"field_link_url": "URL",
|
||||||
|
"field_link_url_error_protocol": "Має бути http або https",
|
||||||
|
"field_link_url_error_url": "Має бути дійсна URL-адреса",
|
||||||
|
"field_number": "Номер",
|
||||||
|
"field_number_sort": "Номер сортування",
|
||||||
|
"field_number_sort_hint": "Ви можете використовувати десяткові числа",
|
||||||
|
"field_release_date": "Дата випуску",
|
||||||
|
"field_release_date_error": "Має бути дійсна дата у форматі РРРР-ММ-ДД",
|
||||||
|
"field_summary": "Короткий зміст",
|
||||||
|
"field_tags": "Теги",
|
||||||
|
"field_title": "Назва",
|
||||||
|
"number_sort_decrement": "Зменшити все на 1",
|
||||||
|
"number_sort_increment": "Збільшити все на 1",
|
||||||
|
"tab_authors": "Автори",
|
||||||
|
"tab_general": "Загальне",
|
||||||
|
"tab_links": "Посилання",
|
||||||
|
"tab_poster": "Плакат",
|
||||||
|
"tab_tags": "Теги",
|
||||||
|
"tags_notice_multiple_edit": "Ви редагуєте теги для кількох книг. Це замінить існуючі теги кожної книги."
|
||||||
|
},
|
||||||
|
"edit_collection": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"dialog_title": "Редагувати колекцію",
|
||||||
|
"field_manual_ordering": "Ручне замовлення",
|
||||||
|
"label_ordering": "За замовчуванням серії в колекції будуть упорядковані за назвою. Ви можете ввімкнути ручне впорядкування, щоб визначити свій власний порядок.",
|
||||||
|
"tab_general": "Загальне",
|
||||||
|
"tab_poster": "Плакат"
|
||||||
|
},
|
||||||
|
"edit_library": {
|
||||||
|
"button_browse": "Переглянути",
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm_add": "Додати",
|
||||||
|
"button_confirm_edit": "Редагувати",
|
||||||
|
"button_next": "Далі",
|
||||||
|
"dialog_title_add": "Додати бібліотеку",
|
||||||
|
"dialot_title_edit": "Редагувати бібліотеку",
|
||||||
|
"field_analysis_analyze_dimensions": "Аналіз розмірів сторінок",
|
||||||
|
"field_analysis_hash_files": "Обчислити хеш для файлів",
|
||||||
|
"field_analysis_hash_koreader": "Обчислити хеш файлів для KOReader",
|
||||||
|
"field_analysis_hash_pages": "Обчислити хеш для сторінок",
|
||||||
|
"field_convert_to_cbz": "Автоматично конвертувати в CBZ",
|
||||||
|
"field_import_barcode_isbn": "Штрих-код ISBN",
|
||||||
|
"field_import_comicinfo_book": "Метадані книги",
|
||||||
|
"field_import_comicinfo_collections": "Колекції",
|
||||||
|
"field_import_comicinfo_readlists": "Списки читання",
|
||||||
|
"field_import_comicinfo_series": "Метадані серіалу",
|
||||||
|
"field_import_comicinfo_series_append_volume": "Додати том до назви серії",
|
||||||
|
"field_import_epub_book": "Метадані книги",
|
||||||
|
"field_import_epub_series": "Метадані серіалу",
|
||||||
|
"field_import_local_artwork": "Місцеві витвори мистецтва",
|
||||||
|
"field_import_mylar_series": "Метадані серіалу",
|
||||||
|
"field_name": "Ім'я",
|
||||||
|
"field_oneshotsdirectory": "Довідник One-Shots",
|
||||||
|
"field_repair_extensions": "Автоматичне виправлення неправильних розширень файлів",
|
||||||
|
"field_root_folder": "Коренева папка",
|
||||||
|
"field_scan_interval": "Інтервал сканування",
|
||||||
|
"field_scanner_empty_trash_after_scan": "Автоматично очищувати кошик після кожного сканування",
|
||||||
|
"field_scanner_force_directory_modified_time": "Примусово змінений час каталогу",
|
||||||
|
"field_scanner_scan_startup": "Сканування під час запуску",
|
||||||
|
"field_series_cover": "Обкладинка серії",
|
||||||
|
"file_browser_dialog_button_confirm": "Виберіть",
|
||||||
|
"file_browser_dialog_title": "Коренева папка бібліотеки",
|
||||||
|
"label_analysis": "Аналізи",
|
||||||
|
"label_file_management": "Керування файлами",
|
||||||
|
"label_import_barcode_isbn": "Імпорт ISBN у штрих-код",
|
||||||
|
"label_import_comicinfo": "Імпорт метаданих для CBR/CBZ, що містять файл ComicInfo.xml",
|
||||||
|
"label_import_epub": "Імпорт метаданих з файлів EPUB",
|
||||||
|
"label_import_local": "Імпорт локальних медіаресурсів",
|
||||||
|
"label_import_mylar": "Імпорт метаданих, згенерованих Mylar",
|
||||||
|
"label_scan_directory_exclusions": "Виключення з каталогу",
|
||||||
|
"label_scan_types": "Сканувати ці типи файлів",
|
||||||
|
"label_scanner": "Сканер",
|
||||||
|
"label_series_cover": "Обкладинка серії",
|
||||||
|
"tab_general": "Загальне",
|
||||||
|
"tab_metadata": "Метадані",
|
||||||
|
"tab_options": "Опції",
|
||||||
|
"tooltip_oneshotsdirectory": "Залиште порожнім, щоб вимкнути",
|
||||||
|
"tooltip_scanner_force_modified_time": "Увімкнути, якщо бібліотека знаходиться на Google Диску",
|
||||||
|
"tooltip_use_resources": "Може споживати багато ресурсів на великих бібліотеках або повільному обладнанні"
|
||||||
|
},
|
||||||
|
"edit_readlist": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"dialog_title": "Редагувати список прочитаних",
|
||||||
|
"field_manual_ordering": "Ручне замовлення",
|
||||||
|
"field_name": "Ім'я",
|
||||||
|
"field_summary": "Короткий зміст",
|
||||||
|
"label_ordering": "За замовчуванням книги у списку прочитання впорядковуються вручну. Ви можете вимкнути ручне впорядкування, щоб сортувати книги за датою випуску.",
|
||||||
|
"tab_general": "Загальне",
|
||||||
|
"tab_poster": "Плакат"
|
||||||
|
},
|
||||||
|
"edit_recommended": {
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"button_reset": "Скинути налаштування за замовчуванням",
|
||||||
|
"dialog_title": "Редагувати рекомендований перегляд"
|
||||||
|
},
|
||||||
|
"edit_series": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"dialog_title_multiple": "Редагувати {count} серій | Редагувати {count} серій",
|
||||||
|
"dialog_title_single": "Редагувати {series}",
|
||||||
|
"field_age_rating": "Віковий рейтинг",
|
||||||
|
"field_age_rating_error": "Віковий рейтинг має бути 0 або більше",
|
||||||
|
"field_genres": "Жанри",
|
||||||
|
"field_labels": "Мітки",
|
||||||
|
"field_language": "Мова",
|
||||||
|
"field_language_hint": "Тег мови IETF BCP 47",
|
||||||
|
"field_publisher": "Видавець",
|
||||||
|
"field_reading_direction": "Напрямок читання",
|
||||||
|
"field_sort_title": "Сортувати заголовок",
|
||||||
|
"field_status": "Статус",
|
||||||
|
"field_summary": "Короткий зміст",
|
||||||
|
"field_tags": "Теги",
|
||||||
|
"field_title": "Назва",
|
||||||
|
"field_total_book_count": "Загальна кількість книг",
|
||||||
|
"field_total_book_count_error": "Загальна кількість книг має бути 1 або більше",
|
||||||
|
"mixed": "ЗМІШАНИЙ",
|
||||||
|
"tab_general": "Загальне",
|
||||||
|
"tab_poster": "Плакат",
|
||||||
|
"tab_sharing": "Спільне використання",
|
||||||
|
"tab_tags": "Теги",
|
||||||
|
"tab_titles": "Альтернативні назви",
|
||||||
|
"tags_notice_multiple_edit": "Ви редагуєте теги для кількох серій. Це замінить існуючі теги кожної серії."
|
||||||
|
},
|
||||||
|
"edit_user": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Зберегти зміни",
|
||||||
|
"dialog_title": "Редагувати користувача",
|
||||||
|
"label_roles_for": "Ролі для {name}"
|
||||||
|
},
|
||||||
|
"edit_user_restrictions": {
|
||||||
|
"age_restriction": {
|
||||||
|
"allow_under": "Дозволити лише під",
|
||||||
|
"exclude_over": "Виключити понад",
|
||||||
|
"none": "Без обмежень"
|
||||||
|
},
|
||||||
|
"edit_restrictions_for": "Редагувати обмеження для {name}",
|
||||||
|
"label_age_restriction": "Вікове обмеження",
|
||||||
|
"label_allow_only_labels": "Дозволити лише мітки",
|
||||||
|
"label_exclude_labels": "Виключити мітки",
|
||||||
|
"tab_content_restrictions": "Обмеження контенту",
|
||||||
|
"tab_shared_libraries": "Спільні бібліотеки"
|
||||||
|
},
|
||||||
|
"empty_trash": {
|
||||||
|
"body": "За замовчуванням медіасервер не видаляє інформацію про медіафайли одразу. Це допомагає, якщо диск тимчасово відключено. Під час очищення кошика бібліотеки вся інформація про відсутні медіафайли видаляється.",
|
||||||
|
"button_confirm": "Порожній",
|
||||||
|
"title": "Очистити кошик для бібліотеки"
|
||||||
|
},
|
||||||
|
"file_browser": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm_default": "Виберіть",
|
||||||
|
"dialog_title_default": "Браузер файлів",
|
||||||
|
"parent_directory": "Батьківський"
|
||||||
|
},
|
||||||
|
"filename_chooser": {
|
||||||
|
"button_choose": "Виберіть",
|
||||||
|
"field_destination_filename": "Ім'я файлу призначення",
|
||||||
|
"label_source_filename": "Ім'я вихідного файлу",
|
||||||
|
"table": {
|
||||||
|
"existing_file": "Існуючий файл",
|
||||||
|
"order": "Замовлення"
|
||||||
|
},
|
||||||
|
"title": "Ім'я файлу призначення'"
|
||||||
|
},
|
||||||
|
"force_kobo_sync": {
|
||||||
|
"dialog_title": "Примусова синхронізація Kobo",
|
||||||
|
"warning_html": "Це видалить всю історію синхронізації для цього ключа API. Ваш Kobo синхронізує все під час наступної синхронізації."
|
||||||
|
},
|
||||||
|
"password_change": {
|
||||||
|
"button_cancel": "Скасувати",
|
||||||
|
"button_confirm": "Змінити пароль",
|
||||||
|
"dialog_title": "Змінити пароль",
|
||||||
|
"field_new_password": "Новий пароль",
|
||||||
|
"field_new_password_error": "Потрібен новий пароль.",
|
||||||
|
"field_repeat_password": "Повторіть новий пароль",
|
||||||
|
"field_repeat_password_error": "Паролі мають бути однаковими."
|
||||||
|
},
|
||||||
|
"refresh_library_metadata": {
|
||||||
|
"body": "Оновлює метадані для всіх медіафайлів у бібліотеці. Залежно від розміру вашої бібліотеки, це може тривати довго.",
|
||||||
|
"button_confirm": "Оновити",
|
||||||
|
"title": "Оновити метадані для бібліотеки"
|
||||||
|
},
|
||||||
|
"series_picker": {
|
||||||
|
"label_search_series": "Пошук серій",
|
||||||
|
"no_results": "Серії не знайдено",
|
||||||
|
"title": "Виберіть серію"
|
||||||
|
},
|
||||||
|
"server_stop": {
|
||||||
|
"button_confirm": "Стій",
|
||||||
|
"confirmation_message": "Ви впевнені, що хочете зупинити Komga?",
|
||||||
|
"dialog_title": "Вимкнути сервер"
|
||||||
|
},
|
||||||
|
"shortcut_help": {
|
||||||
|
"label_description": "Опис",
|
||||||
|
"label_key": "Ключ"
|
||||||
|
},
|
||||||
|
"transient_book_details": {
|
||||||
|
"label_candidate": "Кандидат",
|
||||||
|
"label_existing": "Існуючі",
|
||||||
|
"label_format": "Формат",
|
||||||
|
"label_name": "Ім'я",
|
||||||
|
"label_pages": "Сторінки",
|
||||||
|
"label_size": "Розмір",
|
||||||
|
"pages_table": {
|
||||||
|
"filename": "Ім'я Файлу",
|
||||||
|
"height": "Висота",
|
||||||
|
"index": "Індекс",
|
||||||
|
"media_type": "Тип медіа",
|
||||||
|
"size": "Розмір",
|
||||||
|
"width": "Ширина"
|
||||||
|
},
|
||||||
|
"title": "Деталі книги",
|
||||||
|
"title_comparison": "Порівняння книг"
|
||||||
|
},
|
||||||
|
"transient_book_viewer": {
|
||||||
|
"label_candidate": "Кандидат",
|
||||||
|
"label_existing": "Існуючі",
|
||||||
|
"page_of_pages": "{page} / {pages}",
|
||||||
|
"title": "Перевірити книгу",
|
||||||
|
"title_comparison": "Порівняння книг"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"duplicate_pages": {
|
||||||
|
"action_auto_delete_remaining": "Залишок автоматичного видалення ({count})",
|
||||||
|
"action_delete_auto": "Автоматичне видалення",
|
||||||
|
"action_delete_manual": "Ручне видалення",
|
||||||
|
"action_delete_matches": "Видалити збіги",
|
||||||
|
"action_ignore": "Ігнорувати",
|
||||||
|
"action_ignore_remaining": "Ігнорувати решту ({count})",
|
||||||
|
"action_manual_delete_remaining": "Залишилося ручного видалення ({count})",
|
||||||
|
"confirm_auto_delete_remaining": "Усі хеші сторінок, що залишилися на цій сторінці ({count}), будуть позначені для автоматичного видалення.",
|
||||||
|
"confirm_manual_delete_remaining": "Усі хеші сторінок, що залишилися на цій сторінці ({count}), будуть позначені для ручного видалення.",
|
||||||
|
"delete_to_save": "Видалити, щоб зберегти {size}",
|
||||||
|
"deleted_count": "Видалено {count} разів",
|
||||||
|
"empty_title": "Дублікатів сторінок не знайдено",
|
||||||
|
"empty_title_known": "Немає відомих дублікатів",
|
||||||
|
"filter": {
|
||||||
|
"count": "Кількість",
|
||||||
|
"date_added": "Дата додавання",
|
||||||
|
"date_modified": "Дата зміни",
|
||||||
|
"delete_count": "Кількість видалень",
|
||||||
|
"delete_size": "Зекономлено місце",
|
||||||
|
"match_count": "Кількість матчів",
|
||||||
|
"size": "Розмір",
|
||||||
|
"total_size": "Загальний розмір"
|
||||||
|
},
|
||||||
|
"info": "Видалення дублікатів сторінок призведе до змінення ваших файлів. Створіть резервну копію файлів та видаліть їх вручну, перш ніж використовувати автоматичне видалення.",
|
||||||
|
"known": "Відомий",
|
||||||
|
"matches_n": "Немає збігів | 1 збіг | {count} збігів",
|
||||||
|
"new": "Новий",
|
||||||
|
"saved_size": "Збережено {size}",
|
||||||
|
"title": "Дублікати сторінок",
|
||||||
|
"unknown_size": "Невідомий розмір"
|
||||||
|
},
|
||||||
|
"duplicates": {
|
||||||
|
"file_hash": "Хеш файлу",
|
||||||
|
"size": "Розмір",
|
||||||
|
"title": "Дублікати файлів",
|
||||||
|
"url": "URL"
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"copy_mode": {
|
||||||
|
"HARDLINK": "Жорстке посилання/копіювання файлів",
|
||||||
|
"MOVE": "Переміщення файлів"
|
||||||
|
},
|
||||||
|
"epubreader": {
|
||||||
|
"appearances": {
|
||||||
|
"day": "День",
|
||||||
|
"night": "Ніч",
|
||||||
|
"sepia": "Сепія"
|
||||||
|
},
|
||||||
|
"column_count": {
|
||||||
|
"auto": "Авто",
|
||||||
|
"one": "Один",
|
||||||
|
"two": "Два"
|
||||||
|
},
|
||||||
|
"reading_direction": {
|
||||||
|
"auto": "Автоматичний",
|
||||||
|
"ltr": "Зліва направо",
|
||||||
|
"rtl": "Справа наліво"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"historical_event_type": {
|
||||||
|
"BookConverted": "Книга перетворена",
|
||||||
|
"BookFileDeleted": "Файл книги видалено",
|
||||||
|
"BookImported": "Імпортовано книгу",
|
||||||
|
"DuplicatePageDeleted": "Дублікат сторінки видалено",
|
||||||
|
"SeriesFolderDeleted": "Папку серіалу видалено"
|
||||||
|
},
|
||||||
|
"media_profile": {
|
||||||
|
"DIVINA": "DIVINA",
|
||||||
|
"EPUB": "EPUB",
|
||||||
|
"PDF": "PDF"
|
||||||
|
},
|
||||||
|
"media_status": {
|
||||||
|
"ERROR": "Помилка",
|
||||||
|
"OUTDATED": "Застарілий",
|
||||||
|
"READY": "Готовий",
|
||||||
|
"UNKNOWN": "Невідомо",
|
||||||
|
"UNSUPPORTED": "Не підтримується"
|
||||||
|
},
|
||||||
|
"page_hash_action": {
|
||||||
|
"DELETE_AUTO": "Автоматичне видалення",
|
||||||
|
"DELETE_MANUAL": "Ручне видалення",
|
||||||
|
"IGNORE": "Ігнорувати"
|
||||||
|
},
|
||||||
|
"reading_direction": {
|
||||||
|
"LEFT_TO_RIGHT": "Зліва направо",
|
||||||
|
"RIGHT_TO_LEFT": "Справа наліво",
|
||||||
|
"VERTICAL": "Вертикальний",
|
||||||
|
"WEBTOON": "Вебмультфільм"
|
||||||
|
},
|
||||||
|
"scan_interval": {
|
||||||
|
"DAILY": "Щоденно",
|
||||||
|
"DISABLED": "Вимкнено",
|
||||||
|
"EVERY_12H": "Кожні 12 годин",
|
||||||
|
"EVERY_6H": "Кожні 6 годин",
|
||||||
|
"HOURLY": "Щогодини",
|
||||||
|
"WEEKLY": "Щотижнево"
|
||||||
|
},
|
||||||
|
"series_cover": {
|
||||||
|
"FIRST": "Перший",
|
||||||
|
"FIRST_UNREAD_OR_FIRST": "Спочатку непрочитані, інакше спочатку",
|
||||||
|
"FIRST_UNREAD_OR_LAST": "Спочатку непрочитані, інакше останні",
|
||||||
|
"LAST": "Останній"
|
||||||
|
},
|
||||||
|
"series_status": {
|
||||||
|
"ABANDONED": "Покинутий",
|
||||||
|
"ENDED": "Закінчилося",
|
||||||
|
"HIATUS": "Перерва",
|
||||||
|
"ONGOING": "Поточний"
|
||||||
|
},
|
||||||
|
"thumbnail_size": {
|
||||||
|
"DEFAULT": "За замовчуванням (300 пікселів)",
|
||||||
|
"LARGE": "Великий (900 пікселів)",
|
||||||
|
"MEDIUM": "Середній (600 пікселів)",
|
||||||
|
"XLARGE": "Дуже великий (1200 пікселів)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"epubreader": {
|
||||||
|
"current_chapter": "Поточний розділ",
|
||||||
|
"page_of": "Сторінка {page} з {count}",
|
||||||
|
"publisher_font": "Видавець",
|
||||||
|
"settings": {
|
||||||
|
"column_count": "Кількість стовпців",
|
||||||
|
"font_family": "Шрифт",
|
||||||
|
"layout": "Макет",
|
||||||
|
"layout_paginated": "Пагінована",
|
||||||
|
"layout_scroll": "Прокрутити",
|
||||||
|
"navigation_mode": "Режим навігації",
|
||||||
|
"navigation_options": {
|
||||||
|
"both": "Обидва",
|
||||||
|
"buttons": "Ґудзики",
|
||||||
|
"click": "Клацніть / Торкніться"
|
||||||
|
},
|
||||||
|
"page_margins": "Поля сторінки",
|
||||||
|
"viewing_theme": "Перегляд теми"
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"cycle_pagination": "Циклічна кількість стовпців",
|
||||||
|
"cycle_viewing_theme": "Тема перегляду велосипедів",
|
||||||
|
"font_size_decrease": "Зменшити розмір шрифту",
|
||||||
|
"font_size_increase": "Збільшити розмір шрифту",
|
||||||
|
"menus": "Меню",
|
||||||
|
"next": "Вперед",
|
||||||
|
"previous": "Назад",
|
||||||
|
"reader_navigation": "Навігація читача",
|
||||||
|
"scroll": "Змінити макет на прокручування",
|
||||||
|
"settings": "Налаштування",
|
||||||
|
"show_hide_toc": "Показати/приховати зміст"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error_codes": {
|
||||||
|
"ERR_1000": "Не вдалося отримати доступ до файлу під час аналізу",
|
||||||
|
"ERR_1001": "Тип медіа не підтримується",
|
||||||
|
"ERR_1002": "Зашифровані RAR-архіви не підтримуються",
|
||||||
|
"ERR_1003": "Архів Solid RAR не підтримується",
|
||||||
|
"ERR_1004": "Багатотомні RAR-архіви не підтримуються",
|
||||||
|
"ERR_1005": "Невідома помилка під час аналізу книги",
|
||||||
|
"ERR_1006": "Книга не містить жодної сторінки",
|
||||||
|
"ERR_1007": "Деякі записи не вдалося проаналізувати",
|
||||||
|
"ERR_1008": "Невідома помилка під час отримання записів книги",
|
||||||
|
"ERR_1009": "Список для читання з такою назвою вже існує'",
|
||||||
|
"ERR_1015": "Помилка під час десеріалізації ComicRack CBL",
|
||||||
|
"ERR_1016": "Каталог недоступний або не є каталогом",
|
||||||
|
"ERR_1017": "Не вдається сканувати папку, яка є частиною існуючої бібліотеки",
|
||||||
|
"ERR_1018": "Файл не знайдено",
|
||||||
|
"ERR_1019": "Неможливо імпортувати файл, який є частиною існуючої бібліотеки",
|
||||||
|
"ERR_1020": "Книга для оновлення не належить до наданої серії",
|
||||||
|
"ERR_1021": "Цільовий файл вже існує",
|
||||||
|
"ERR_1022": "Не вдалося відсканувати нещодавно імпортовану книгу",
|
||||||
|
"ERR_1023": "Книга вже є у списку для читання",
|
||||||
|
"ERR_1024": "Помилка входу OAuth2: немає атрибута електронної пошти",
|
||||||
|
"ERR_1025": "Помилка входу OAuth2: локального користувача з такою електронною адресою не існує",
|
||||||
|
"ERR_1026": "Помилка входу в OpenID Connect: електронна адреса не підтверджена",
|
||||||
|
"ERR_1027": "Помилка входу в OpenID Connect: немає атрибута email_verified",
|
||||||
|
"ERR_1028": "Помилка входу в OpenID Connect: немає атрибута електронної пошти",
|
||||||
|
"ERR_1029": "ComicRack CBL не містить жодного елемента Book",
|
||||||
|
"ERR_1030": "ComicRack CBL не має елемента Name",
|
||||||
|
"ERR_1031": "У книзі ComicRack CBL відсутня серія або номер",
|
||||||
|
"ERR_1032": "Файл EPUB має неправильний тип медіафайлу",
|
||||||
|
"ERR_1033": "Деякі записи відсутні",
|
||||||
|
"ERR_1034": "Ключ API з цим коментарем вже існує",
|
||||||
|
"ERR_1035": "Помилка під час отримання змісту EPUB",
|
||||||
|
"ERR_1036": "Помилка під час отримання орієнтирів EPUB",
|
||||||
|
"ERR_1037": "Помилка під час отримання списку сторінок EPUB",
|
||||||
|
"ERR_1038": "Помилка під час отримання сторінок EPUB divina",
|
||||||
|
"ERR_1039": "Помилка під час отримання позицій EPUB"
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"age_rating": "віковий рейтинг",
|
||||||
|
"age_rating_none": "Жоден",
|
||||||
|
"any": "Будь-який",
|
||||||
|
"complete": "Завершено",
|
||||||
|
"genre": "жанр",
|
||||||
|
"in_progress": "У процесі",
|
||||||
|
"language": "мова",
|
||||||
|
"library": "бібліотека",
|
||||||
|
"media_profile": "Медіа-профіль",
|
||||||
|
"media_status": "Стан медіа",
|
||||||
|
"oneshot": "Одноразовий",
|
||||||
|
"publisher": "видавець",
|
||||||
|
"read": "Читати",
|
||||||
|
"release_date": "дата випуску",
|
||||||
|
"sharing_label": "Мітка спільного доступу",
|
||||||
|
"status": "статус",
|
||||||
|
"tag": "тег",
|
||||||
|
"unread": "Непрочитане"
|
||||||
|
},
|
||||||
|
"filter_drawer": {
|
||||||
|
"filter": "фільтр",
|
||||||
|
"sort": "сортувати"
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"header": {
|
||||||
|
"book": "Книга",
|
||||||
|
"date": "Дата",
|
||||||
|
"details": "Деталі",
|
||||||
|
"series": "Серія",
|
||||||
|
"type": "Тип"
|
||||||
|
},
|
||||||
|
"title": "Історія"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"theme": "Тема",
|
||||||
|
"translation": "Переклад"
|
||||||
|
},
|
||||||
|
"library_navigation": {
|
||||||
|
"browse": "Переглянути",
|
||||||
|
"browse_books": "Книги",
|
||||||
|
"browse_series": "Серія",
|
||||||
|
"collections": "Колекції",
|
||||||
|
"readlists": "Списки для читання",
|
||||||
|
"recommended": "Рекомендовано"
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"create_user_account": "Створити обліковий запис користувача",
|
||||||
|
"login": "Увійти",
|
||||||
|
"unclaimed_html": "Цей сервер Komga ще не активний, вам потрібно створити обліковий запис користувача, щоб мати до нього доступ.<br><br>Виберіть <strong>електронну пошту</strong> та <strong>пароль</strong> і натисніть <strong>Створити обліковий запис користувача</strong>."
|
||||||
|
},
|
||||||
|
"media_analysis": {
|
||||||
|
"comment": "Коментар",
|
||||||
|
"media_analysis": "Медіа-аналіз",
|
||||||
|
"media_type": "Тип носія",
|
||||||
|
"name": "Ім'я",
|
||||||
|
"size": "Розмір",
|
||||||
|
"status": "Статус",
|
||||||
|
"url": "URL"
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"add_to_collection": "Додати до колекції",
|
||||||
|
"add_to_readlist": "Додати до списку прочитання",
|
||||||
|
"analyze": "Аналіз",
|
||||||
|
"bulk_edit_metadata": "Масове редагування метаданих",
|
||||||
|
"delete": "Видалити",
|
||||||
|
"deselect_all": "Зняти вибір усіх",
|
||||||
|
"download_readlist": "Завантажити список для читання",
|
||||||
|
"download_series": "Завантажити серію",
|
||||||
|
"edit": "Редагувати",
|
||||||
|
"edit_metadata": "Редагувати метадані",
|
||||||
|
"empty_trash": "Очистити кошик",
|
||||||
|
"mark_read": "Позначити як прочитане",
|
||||||
|
"mark_unread": "Позначити як непрочитане",
|
||||||
|
"pin": "Закріпити",
|
||||||
|
"refresh_metadata": "Оновити метадані",
|
||||||
|
"scan_library_files": "Сканування файлів бібліотеки",
|
||||||
|
"scan_library_files_deep": "Сканувати файли бібліотеки (глибоко)",
|
||||||
|
"select_all": "Вибрати все",
|
||||||
|
"unpin": "Відкріпити"
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"library_books": "Книги на бібліотеку",
|
||||||
|
"library_disk_space": "Місце на диску бібліотеки",
|
||||||
|
"library_series": "Серії на бібліотеку",
|
||||||
|
"library_sidecars": "Коляски на бібліотеку",
|
||||||
|
"tasks_executed": "Виконані завдання",
|
||||||
|
"tasks_total_time": "Загальний час виконання завдань",
|
||||||
|
"title": "Метрики"
|
||||||
|
},
|
||||||
|
"missing_posters": {
|
||||||
|
"title": "Відсутні плакати"
|
||||||
|
},
|
||||||
|
"navigation": {
|
||||||
|
"home": "Дім",
|
||||||
|
"libraries": "Бібліотеки",
|
||||||
|
"logout": "Вийти"
|
||||||
|
},
|
||||||
|
"no_libraries_pinned": {
|
||||||
|
"subtitle": "Ви можете закріпити бібліотеку з меню з трьома крапками",
|
||||||
|
"title": "Немає закріплених бібліотек"
|
||||||
|
},
|
||||||
|
"page_not_found": {
|
||||||
|
"go_back_to_home_page": "Повернутися на головну сторінку",
|
||||||
|
"page_does_not_exist": "Сторінка, яку ви шукаєте, не існує.",
|
||||||
|
"page_not_found": "Сторінку не знайдено"
|
||||||
|
},
|
||||||
|
"read_more": {
|
||||||
|
"less": "Читати менше",
|
||||||
|
"more": "Читати більше"
|
||||||
|
},
|
||||||
|
"readlist_import": {
|
||||||
|
"row": {
|
||||||
|
"duplicate_book": "Дублікат книги",
|
||||||
|
"error_choose_book": "Виберіть у книгу"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"readlists_expansion_panel": {
|
||||||
|
"manage_readlist": "Керування списком прочитаних",
|
||||||
|
"title": "Список прочитаного {name}"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"no_results": "Пошук не дав результатів",
|
||||||
|
"search": "Пошук",
|
||||||
|
"search_for_something_else": "Спробуйте пошукати щось інше",
|
||||||
|
"search_results_for": "Результати пошуку для \"{name}\""
|
||||||
|
},
|
||||||
|
"searchbox": {
|
||||||
|
"in_library": "З {library}",
|
||||||
|
"no_results": "Немає результатів",
|
||||||
|
"search_all": "Шукати все…"
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"server_management": {
|
||||||
|
"button_cancel_all_tasks": "Скасувати всі завдання",
|
||||||
|
"button_empty_trash": "Очистити кошик для всіх бібліотек",
|
||||||
|
"button_scan_libraries": "Сканувати всі бібліотеки",
|
||||||
|
"button_scan_libraries_deep": "Сканувати всі бібліотеки (глибоко)",
|
||||||
|
"button_shutdown": "Вимкнути",
|
||||||
|
"download_log": "Завантажити файл журналу",
|
||||||
|
"notification_tasks_cancelled": "Немає завдань для скасування | Одне завдання скасовано | {count} завдань скасовано",
|
||||||
|
"section_title": "Керування сервером"
|
||||||
|
},
|
||||||
|
"tab_title": "Сервер",
|
||||||
|
"updates": "Оновлення"
|
||||||
|
},
|
||||||
|
"server_settings": {
|
||||||
|
"config_precedence": "Має пріоритет над файлом конфігурації",
|
||||||
|
"dialog_regenerate_thumbnails": {
|
||||||
|
"body": "Розмір мініатюр змінився. Бажаєте створити мініатюри книг заново?",
|
||||||
|
"btn_alternate": "Так, усі книги",
|
||||||
|
"btn_cancel": "Ні",
|
||||||
|
"btn_confirm": "Так, але тільки якщо більший",
|
||||||
|
"title": "Згенерувати мініатюри знову"
|
||||||
|
},
|
||||||
|
"hint_kobo_port": "Встановлювати лише у разі проблем із синхронізацією обкладинок та завантажень",
|
||||||
|
"label_delete_empty_collections": "Видалити порожні колекції після сканування",
|
||||||
|
"label_delete_empty_readlists": "Видалити порожні списки прочитання після сканування",
|
||||||
|
"label_kepubify_path": "Шлях до kepubify",
|
||||||
|
"label_kobo_port": "Зовнішній порт Kobo Sync",
|
||||||
|
"label_kobo_proxy": "Запити синхронізації проксі-сервера Kobo до магазину Kobo",
|
||||||
|
"label_rememberme_duration": "Тривалість дії функції «Запам’ятати мене» (у днях)",
|
||||||
|
"label_server_context_path": "Базова URL-адреса",
|
||||||
|
"label_server_port": "Порт сервера",
|
||||||
|
"label_task_pool_size": "Гілки завдань",
|
||||||
|
"label_thumbnail_size": "Розмір мініатюр",
|
||||||
|
"requires_restart": "Потрібен перезапуск, щоб набути чинності",
|
||||||
|
"server_settings": "Налаштування сервера"
|
||||||
|
},
|
||||||
|
"settings_user": {
|
||||||
|
"change_password": "Змінити пароль",
|
||||||
|
"edit_restrictions": "Редагувати обмеження",
|
||||||
|
"edit_user": "Редагувати користувача",
|
||||||
|
"latest_activity": "Остання активність: {date}",
|
||||||
|
"no_recent_activity": "Немає нещодавньої активності",
|
||||||
|
"role_administrator": "Адміністратор",
|
||||||
|
"role_user": "Користувач"
|
||||||
|
},
|
||||||
|
"sort": {
|
||||||
|
"books_count": "Кількість книг",
|
||||||
|
"date_added": "Дата додавання",
|
||||||
|
"date_read": "Дата прочитання",
|
||||||
|
"date_updated": "Дата оновлення",
|
||||||
|
"file_name": "Ім'я файлу",
|
||||||
|
"file_size": "Розмір файлу",
|
||||||
|
"folder_name": "Назва папки",
|
||||||
|
"name": "Ім'я",
|
||||||
|
"number": "Номер",
|
||||||
|
"page_count": "Кількість сторінок",
|
||||||
|
"random": "Випадкове",
|
||||||
|
"release_date": "Дата випуску'",
|
||||||
|
"series": "Серія"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"dark": "Темний",
|
||||||
|
"light": "Світло",
|
||||||
|
"system": "Система"
|
||||||
|
},
|
||||||
|
"thumbnail_card": {
|
||||||
|
"tooltip_delete": "Видалити",
|
||||||
|
"tooltip_generated": "Згенеровані ілюстрації",
|
||||||
|
"tooltip_mark_as_selected": "Позначити як вибране",
|
||||||
|
"tooltip_selected": "Вибрано",
|
||||||
|
"tooltip_sidecar": "Місцеві витвори мистецтва",
|
||||||
|
"tooltip_to_be_deleted": "Буде видалено",
|
||||||
|
"tooltip_to_be_uploaded": "Для завантаження",
|
||||||
|
"tooltip_too_big": "Файл занадто великий!",
|
||||||
|
"tooltip_user_uploaded": "Завантажено користувачем"
|
||||||
|
},
|
||||||
|
"titles_more": {
|
||||||
|
"less": "Менше назв",
|
||||||
|
"more": "Більше назв"
|
||||||
|
},
|
||||||
|
"ui_settings": {
|
||||||
|
"general": "Загальне",
|
||||||
|
"label_oauth2_auto_login": "Автоматичний вхід OAuth2",
|
||||||
|
"label_oauth2_hide_login": "Приховати поля входу, якщо ввімкнено OAuth2",
|
||||||
|
"label_poster_blur_unread": "Розмиття плаката для непрочитаних книг та серій",
|
||||||
|
"label_poster_stretch": "Розтягніть плакат, щоб він підходив до листівки",
|
||||||
|
"label_series_groups": "Групування серій",
|
||||||
|
"section_oauth2": "OAuth2",
|
||||||
|
"series_groups": {
|
||||||
|
"alpha": "Алфавітний",
|
||||||
|
"japanese": "Годзюон (японська)"
|
||||||
|
},
|
||||||
|
"tooltip_oauth2_auto_login": "Потрібен один постачальник OAuth2 та ввімкнена функція «приховувати поля входу»"
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"available": "Доступні оновлення",
|
||||||
|
"latest_installed": "Остання версія Komga вже встановлена"
|
||||||
|
},
|
||||||
|
"user_roles": {
|
||||||
|
"ADMIN": "Адміністратор",
|
||||||
|
"FILE_DOWNLOAD": "Завантаження файлу",
|
||||||
|
"KOBO_SYNC": "Синхронізація Kobo",
|
||||||
|
"KOREADER_SYNC": "Синхронізація KOReader",
|
||||||
|
"PAGE_STREAMING": "Потокове передавання сторінок",
|
||||||
|
"USER": "Користувач"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"api_keys": "Ключі API",
|
||||||
|
"authentication_activity": "Активність автентифікації",
|
||||||
|
"users": "Користувачі"
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"context_path": "Повинно починатися з '/', не закінчуватися на '/-_' та містити лише '/-_a-z0-9'",
|
||||||
|
"one_or_more": "Має бути 1 або більше",
|
||||||
|
"tcp_port": "Має бути від 1 до 65535",
|
||||||
|
"zero_or_more": "Має бути 0 або більше"
|
||||||
|
},
|
||||||
|
"welcome": {
|
||||||
|
"add_library": "Додати бібліотеку'",
|
||||||
|
"no_libraries_yet": "Ще не додано жодної бібліотеки!",
|
||||||
|
"welcome_message": "Ласкаво просимо до Komga"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -906,14 +906,14 @@ export default Vue.extend({
|
||||||
}, 50),
|
}, 50),
|
||||||
downloadCurrentPage() {
|
downloadCurrentPage() {
|
||||||
new jsFileDownloader({
|
new jsFileDownloader({
|
||||||
url: this.currentPage.url,
|
url: `${this.currentPage.url}?contentNegotiation=false`,
|
||||||
filename: `${this.book.name}-${this.currentPage.number}.${this.currentPage.fileName.split('.').pop()}`,
|
filename: `${this.book.name}-${this.currentPage.number}.${this.currentPage.fileName.split('.').pop()}`,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
forceDesktopMode: true,
|
forceDesktopMode: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async setCurrentPageAsPoster(type: ItemTypes) {
|
async setCurrentPageAsPoster(type: ItemTypes) {
|
||||||
const imageFile = await getFileFromUrl(this.currentPage.url, 'poster', 'image/jpeg', {credentials: 'include'})
|
const imageFile = await getFileFromUrl(`${this.currentPage.url}?contentNegotiation=false`, 'poster', 'image/jpeg', {credentials: 'include'})
|
||||||
const newImageFile = await resizeImageFile(imageFile)
|
const newImageFile = await resizeImageFile(imageFile)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ItemTypes.BOOK:
|
case ItemTypes.BOOK:
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ import org.apache.tools.ant.taskdefs.condition.Os
|
||||||
import org.flywaydb.gradle.task.FlywayMigrateTask
|
import org.flywaydb.gradle.task.FlywayMigrateTask
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
import org.jetbrains.kotlin.util.prefixIfNot
|
import org.jetbrains.kotlin.util.prefixIfNot
|
||||||
|
import org.springframework.boot.gradle.plugin.SpringBootPlugin
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
kotlin("plugin.spring")
|
kotlin("plugin.spring")
|
||||||
kotlin("kapt")
|
kotlin("kapt")
|
||||||
id("org.springframework.boot") version "3.5.4"
|
id("org.springframework.boot") version libs.versions.springboot.get()
|
||||||
id("com.gorylenko.gradle-git-properties") version "2.5.2"
|
alias(libs.plugins.gradleGitProperties)
|
||||||
id("nu.studer.jooq") version "10.1"
|
id("nu.studer.jooq") version "10.1"
|
||||||
id("org.flywaydb.flyway") version "11.7.2"
|
id("org.flywaydb.flyway") version "11.7.2"
|
||||||
id("com.github.johnrengelman.processes") version "0.5.0"
|
id("com.github.johnrengelman.processes") version "0.5.0"
|
||||||
|
|
@ -37,7 +38,7 @@ dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
implementation(kotlin("reflect"))
|
implementation(kotlin("reflect"))
|
||||||
|
|
||||||
api(platform("org.springframework.boot:spring-boot-dependencies:3.5.4"))
|
api(platform(SpringBootPlugin.BOM_COORDINATES))
|
||||||
|
|
||||||
api("org.springframework.boot:spring-boot-starter-web")
|
api("org.springframework.boot:spring-boot-starter-web")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||||
|
|
@ -51,7 +52,7 @@ dependencies {
|
||||||
implementation("com.github.gotson:spring-session-caffeine:2.1.0")
|
implementation("com.github.gotson:spring-session-caffeine:2.1.0")
|
||||||
implementation("org.springframework.data:spring-data-commons")
|
implementation("org.springframework.data:spring-data-commons")
|
||||||
|
|
||||||
kapt("org.springframework.boot:spring-boot-configuration-processor:3.5.4")
|
kapt("org.springframework.boot:spring-boot-configuration-processor:${libs.versions.springboot.get()}")
|
||||||
|
|
||||||
implementation("org.flywaydb:flyway-core")
|
implementation("org.flywaydb:flyway-core")
|
||||||
|
|
||||||
|
|
@ -66,14 +67,10 @@ dependencies {
|
||||||
implementation("org.apache.commons:commons-lang3:3.18.0")
|
implementation("org.apache.commons:commons-lang3:3.18.0")
|
||||||
implementation("commons-validator:commons-validator:1.10.0")
|
implementation("commons-validator:commons-validator:1.10.0")
|
||||||
|
|
||||||
run {
|
implementation("org.apache.lucene:lucene-core:${libs.versions.lucene.get()}")
|
||||||
// v10 requires JDK 21
|
implementation("org.apache.lucene:lucene-analysis-common:${libs.versions.lucene.get()}")
|
||||||
val luceneVersion = "9.9.1"
|
implementation("org.apache.lucene:lucene-queryparser:${libs.versions.lucene.get()}")
|
||||||
implementation("org.apache.lucene:lucene-core:$luceneVersion")
|
implementation("org.apache.lucene:lucene-backward-codecs:${libs.versions.lucene.get()}")
|
||||||
implementation("org.apache.lucene:lucene-analysis-common:$luceneVersion")
|
|
||||||
implementation("org.apache.lucene:lucene-queryparser:$luceneVersion")
|
|
||||||
implementation("org.apache.lucene:lucene-backward-codecs:$luceneVersion")
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation("com.ibm.icu:icu4j:77.1")
|
implementation("com.ibm.icu:icu4j:77.1")
|
||||||
|
|
||||||
|
|
@ -82,18 +79,18 @@ dependencies {
|
||||||
implementation("org.apache.tika:tika-core:2.9.1")
|
implementation("org.apache.tika:tika-core:2.9.1")
|
||||||
implementation("org.apache.commons:commons-compress:1.27.1")
|
implementation("org.apache.commons:commons-compress:1.27.1")
|
||||||
implementation("com.github.junrar:junrar:7.5.5")
|
implementation("com.github.junrar:junrar:7.5.5")
|
||||||
implementation("com.github.gotson.nightcompress:nightcompress:1.1.0")
|
implementation("com.github.gotson.nightcompress:nightcompress:1.1.1")
|
||||||
implementation("org.apache.pdfbox:pdfbox:3.0.5")
|
implementation("org.apache.pdfbox:pdfbox:3.0.5")
|
||||||
implementation("net.grey-panther:natural-comparator:1.1")
|
implementation("net.grey-panther:natural-comparator:1.1")
|
||||||
implementation("org.jsoup:jsoup:1.18.3")
|
implementation("org.jsoup:jsoup:1.21.1")
|
||||||
|
|
||||||
implementation("net.coobird:thumbnailator:0.4.20")
|
implementation("net.coobird:thumbnailator:0.4.20")
|
||||||
runtimeOnly("com.twelvemonkeys.imageio:imageio-jpeg:3.12.0")
|
runtimeOnly("com.twelvemonkeys.imageio:imageio-jpeg:${libs.versions.twelvemonkeys.get()}")
|
||||||
runtimeOnly("com.twelvemonkeys.imageio:imageio-tiff:3.12.0")
|
runtimeOnly("com.twelvemonkeys.imageio:imageio-tiff:${libs.versions.twelvemonkeys.get()}")
|
||||||
runtimeOnly("com.twelvemonkeys.imageio:imageio-webp:3.12.0")
|
runtimeOnly("com.twelvemonkeys.imageio:imageio-webp:${libs.versions.twelvemonkeys.get()}")
|
||||||
runtimeOnly("com.github.gotson.nightmonkeys:imageio-jxl:1.0.0")
|
runtimeOnly("com.github.gotson.nightmonkeys:imageio-jxl:${libs.versions.nightmonkeys.get()}")
|
||||||
runtimeOnly("com.github.gotson.nightmonkeys:imageio-heif:1.0.0")
|
runtimeOnly("com.github.gotson.nightmonkeys:imageio-heif:${libs.versions.nightmonkeys.get()}")
|
||||||
runtimeOnly("com.github.gotson.nightmonkeys:imageio-webp:1.0.0")
|
runtimeOnly("com.github.gotson.nightmonkeys:imageio-webp:${libs.versions.nightmonkeys.get()}")
|
||||||
// support for jpeg2000
|
// support for jpeg2000
|
||||||
runtimeOnly("com.github.jai-imageio:jai-imageio-jpeg2000:1.4.0")
|
runtimeOnly("com.github.jai-imageio:jai-imageio-jpeg2000:1.4.0")
|
||||||
runtimeOnly("org.apache.pdfbox:jbig2-imageio:3.0.4")
|
runtimeOnly("org.apache.pdfbox:jbig2-imageio:3.0.4")
|
||||||
|
|
@ -107,8 +104,8 @@ dependencies {
|
||||||
|
|
||||||
implementation("com.github.ben-manes.caffeine:caffeine")
|
implementation("com.github.ben-manes.caffeine:caffeine")
|
||||||
|
|
||||||
implementation("org.xerial:sqlite-jdbc:3.50.2.0")
|
implementation("org.xerial:sqlite-jdbc:${libs.versions.sqliteJdbc.get()}")
|
||||||
jooqGenerator("org.xerial:sqlite-jdbc:3.50.2.0")
|
jooqGenerator("org.xerial:sqlite-jdbc:${libs.versions.sqliteJdbc.get()}")
|
||||||
|
|
||||||
if (version.toString().endsWith(".0.0")) {
|
if (version.toString().endsWith(".0.0")) {
|
||||||
ksp("com.github.gotson.bestbefore:bestbefore-processor-kotlin:0.2.0")
|
ksp("com.github.gotson.bestbefore:bestbefore-processor-kotlin:0.2.0")
|
||||||
|
|
@ -127,9 +124,9 @@ dependencies {
|
||||||
benchmarkImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
|
benchmarkImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
|
||||||
benchmarkImplementation("org.openjdk.jmh:jmh-core:1.37")
|
benchmarkImplementation("org.openjdk.jmh:jmh-core:1.37")
|
||||||
kaptBenchmark("org.openjdk.jmh:jmh-generator-annprocess:1.37")
|
kaptBenchmark("org.openjdk.jmh:jmh-generator-annprocess:1.37")
|
||||||
kaptBenchmark("org.springframework.boot:spring-boot-configuration-processor:3.5.4")
|
kaptBenchmark("org.springframework.boot:spring-boot-configuration-processor:${libs.versions.springboot.get()}")
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools:3.5.4")
|
developmentOnly("org.springframework.boot:spring-boot-devtools:${libs.versions.springboot.get()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
|
@ -306,13 +303,13 @@ tasks.register("flywayMigrateTasks", FlywayMigrateTask::class) {
|
||||||
buildscript {
|
buildscript {
|
||||||
configurations["classpath"].resolutionStrategy.eachDependency {
|
configurations["classpath"].resolutionStrategy.eachDependency {
|
||||||
if (requested.group.startsWith("org.jooq") && requested.name.startsWith("jooq")) {
|
if (requested.group.startsWith("org.jooq") && requested.name.startsWith("jooq")) {
|
||||||
useVersion("3.19.24")
|
useVersion(libs.versions.jooq.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jooq {
|
jooq {
|
||||||
version = "3.19.24"
|
version = libs.versions.jooq.get()
|
||||||
configurations {
|
configurations {
|
||||||
create("main") {
|
create("main") {
|
||||||
jooqConfiguration.apply {
|
jooqConfiguration.apply {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ FROM ubuntu:24.10 as build-amd64
|
||||||
ENV JAVA_HOME=/opt/java/openjdk
|
ENV JAVA_HOME=/opt/java/openjdk
|
||||||
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
||||||
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
||||||
RUN apt -y update && \
|
RUN sed -i -re 's/([a-z]{2}\.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list.d/ubuntu.sources && \
|
||||||
|
apt -y update && \
|
||||||
apt -y install ca-certificates locales libjxl-dev libheif-dev libwebp-dev libarchive-dev wget curl && \
|
apt -y install ca-certificates locales libjxl-dev libheif-dev libwebp-dev libarchive-dev wget curl && \
|
||||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \
|
||||||
locale-gen en_US.UTF-8 && \
|
locale-gen en_US.UTF-8 && \
|
||||||
|
|
@ -23,7 +24,8 @@ FROM ubuntu:24.10 as build-arm64
|
||||||
ENV JAVA_HOME=/opt/java/openjdk
|
ENV JAVA_HOME=/opt/java/openjdk
|
||||||
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
|
||||||
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
ENV PATH="${JAVA_HOME}/bin:${PATH}"
|
||||||
RUN apt -y update && \
|
RUN sed -i -re 's/([a-z]{2}\.)?ports.ubuntu.com\/ubuntu-ports/old-releases.ubuntu.com\/ubuntu/g' /etc/apt/sources.list.d/ubuntu.sources && \
|
||||||
|
apt -y update && \
|
||||||
apt -y install ca-certificates locales libjxl-dev libheif-dev libwebp-dev libarchive-dev wget curl && \
|
apt -y install ca-certificates locales libjxl-dev libheif-dev libwebp-dev libarchive-dev wget curl && \
|
||||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \
|
||||||
locale-gen en_US.UTF-8 && \
|
locale-gen en_US.UTF-8 && \
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"url": "https://github.com/gotson/komga/blob/master/LICENSE"
|
"url": "https://github.com/gotson/komga/blob/master/LICENSE"
|
||||||
},
|
},
|
||||||
"title": "Komga API",
|
"title": "Komga API",
|
||||||
"version": "1.23.1"
|
"version": "1.23.6"
|
||||||
},
|
},
|
||||||
"externalDocs": {
|
"externalDocs": {
|
||||||
"description": "Komga documentation",
|
"description": "Komga documentation",
|
||||||
|
|
@ -4919,7 +4919,7 @@
|
||||||
"operationId": "matchComicRackList",
|
"operationId": "matchComicRackList",
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"multipart/form-data": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -10313,6 +10313,9 @@
|
||||||
"bookId": {
|
"bookId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
|
|
@ -10331,6 +10334,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
"id",
|
||||||
"properties",
|
"properties",
|
||||||
"timestamp",
|
"timestamp",
|
||||||
"type"
|
"type"
|
||||||
|
|
@ -13082,7 +13086,9 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"kepubifyPath": {
|
"kepubifyPath": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"deprecated": true,
|
||||||
|
"description": "Will be removed in a future version"
|
||||||
},
|
},
|
||||||
"koboPort": {
|
"koboPort": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ class BookLifecycle(
|
||||||
val extension =
|
val extension =
|
||||||
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
||||||
?: throw IllegalArgumentException("Epub extension not found")
|
?: throw IllegalArgumentException("Epub extension not found")
|
||||||
|
.also { logger.error { "Epub extension not found for book ${book.id}. Book should be re-analyzed." } }
|
||||||
extension.positions[page - 1]
|
extension.positions[page - 1]
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|
@ -496,6 +497,7 @@ class BookLifecycle(
|
||||||
val extension =
|
val extension =
|
||||||
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
||||||
?: throw IllegalArgumentException("Epub extension not found")
|
?: throw IllegalArgumentException("Epub extension not found")
|
||||||
|
.also { logger.error { "Epub extension not found for book ${book.id}. Book should be re-analyzed." } }
|
||||||
// match progression with positions
|
// match progression with positions
|
||||||
val matchingPositions = extension.positions.filter { it.href == href }
|
val matchingPositions = extension.positions.filter { it.href == href }
|
||||||
val matchedPosition =
|
val matchedPosition =
|
||||||
|
|
|
||||||
|
|
@ -113,13 +113,13 @@ class ReadListLifecycle(
|
||||||
|
|
||||||
fun deleteEmptyReadLists() {
|
fun deleteEmptyReadLists() {
|
||||||
logger.info { "Deleting empty read lists" }
|
logger.info { "Deleting empty read lists" }
|
||||||
|
val toDelete = readListRepository.findAllEmpty()
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
val toDelete = readListRepository.findAllEmpty()
|
|
||||||
thumbnailReadListRepository.deleteByReadListIds(toDelete.map { it.id })
|
thumbnailReadListRepository.deleteByReadListIds(toDelete.map { it.id })
|
||||||
readListRepository.delete(toDelete.map { it.id })
|
readListRepository.delete(toDelete.map { it.id })
|
||||||
|
|
||||||
toDelete.forEach { eventPublisher.publishEvent(DomainEvent.ReadListDeleted(it)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toDelete.forEach { eventPublisher.publishEvent(DomainEvent.ReadListDeleted(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addThumbnail(thumbnail: ThumbnailReadList): ThumbnailReadList {
|
fun addThumbnail(thumbnail: ThumbnailReadList): ThumbnailReadList {
|
||||||
|
|
|
||||||
|
|
@ -99,13 +99,13 @@ class SeriesCollectionLifecycle(
|
||||||
|
|
||||||
fun deleteEmptyCollections() {
|
fun deleteEmptyCollections() {
|
||||||
logger.info { "Deleting empty collections" }
|
logger.info { "Deleting empty collections" }
|
||||||
|
val toDelete = collectionRepository.findAllEmpty()
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
val toDelete = collectionRepository.findAllEmpty()
|
|
||||||
thumbnailSeriesCollectionRepository.deleteByCollectionIds(toDelete.map { it.id })
|
thumbnailSeriesCollectionRepository.deleteByCollectionIds(toDelete.map { it.id })
|
||||||
collectionRepository.delete(toDelete.map { it.id })
|
collectionRepository.delete(toDelete.map { it.id })
|
||||||
|
|
||||||
toDelete.forEach { eventPublisher.publishEvent(DomainEvent.CollectionDeleted(it)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toDelete.forEach { eventPublisher.publishEvent(DomainEvent.CollectionDeleted(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addThumbnail(thumbnail: ThumbnailSeriesCollection): ThumbnailSeriesCollection {
|
fun addThumbnail(thumbnail: ThumbnailSeriesCollection): ThumbnailSeriesCollection {
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class KomgaProperties {
|
||||||
@get:Positive
|
@get:Positive
|
||||||
var maxPoolSize: Int = 1
|
var maxPoolSize: Int = 1
|
||||||
|
|
||||||
var journalMode: JournalMode? = null
|
var journalMode: JournalMode? = JournalMode.WAL
|
||||||
|
|
||||||
@DurationUnit(ChronoUnit.SECONDS)
|
@DurationUnit(ChronoUnit.SECONDS)
|
||||||
var busyTimeout: Duration? = null
|
var busyTimeout: Duration? = null
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ class Hasher {
|
||||||
return computeHash(path.inputStream())
|
return computeHash(path.inputStream())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun computeHash(string: String): String = computeHash(string.byteInputStream())
|
||||||
|
|
||||||
fun computeHash(stream: InputStream): String {
|
fun computeHash(stream: InputStream): String {
|
||||||
val hash = Algorithm.XXH3_128.Seeded(SEED.toLong()).createDigest()
|
val hash = Algorithm.XXH3_128.Seeded(SEED.toLong()).createDigest()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.gotson.komga.infrastructure.jooq
|
||||||
|
|
||||||
|
import org.jooq.DSLContext
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
|
|
||||||
|
abstract class SplitDslDaoBase {
|
||||||
|
val dslRW: DSLContext
|
||||||
|
private val _dslRO: DSLContext
|
||||||
|
|
||||||
|
constructor(dslRW: DSLContext, dslRO: DSLContext) {
|
||||||
|
this.dslRW = dslRW
|
||||||
|
this._dslRO = dslRO
|
||||||
|
}
|
||||||
|
|
||||||
|
val dslRO: DSLContext
|
||||||
|
get() =
|
||||||
|
if (TransactionSynchronizationManager.isActualTransactionActive() && !TransactionSynchronizationManager.isCurrentTransactionReadOnly())
|
||||||
|
dslRW
|
||||||
|
else
|
||||||
|
_dslRO
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.AuthenticationActivity
|
import org.gotson.komga.domain.model.AuthenticationActivity
|
||||||
import org.gotson.komga.domain.model.KomgaUser
|
import org.gotson.komga.domain.model.KomgaUser
|
||||||
import org.gotson.komga.domain.persistence.AuthenticationActivityRepository
|
import org.gotson.komga.domain.persistence.AuthenticationActivityRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.AuthenticationActivityRecord
|
import org.gotson.komga.jooq.main.tables.records.AuthenticationActivityRecord
|
||||||
|
|
@ -21,9 +22,10 @@ import java.time.LocalDateTime
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class AuthenticationActivityDao(
|
class AuthenticationActivityDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : AuthenticationActivityRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
AuthenticationActivityRepository {
|
||||||
private val aa = Tables.AUTHENTICATION_ACTIVITY
|
private val aa = Tables.AUTHENTICATION_ACTIVITY
|
||||||
|
|
||||||
private val sorts =
|
private val sorts =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.gotson.komga.infrastructure.jooq.main
|
package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
import org.gotson.komga.domain.model.ContentRestrictions
|
import org.gotson.komga.domain.model.ContentRestrictions
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.toCondition
|
import org.gotson.komga.infrastructure.jooq.toCondition
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -19,8 +20,9 @@ import java.time.LocalDateTime
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class BookCommonDao(
|
class BookCommonDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
) {
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
|
) : SplitDslDaoBase(dslRW, dslRO) {
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import org.gotson.komga.domain.model.SearchContext
|
||||||
import org.gotson.komga.domain.persistence.BookRepository
|
import org.gotson.komga.domain.persistence.BookRepository
|
||||||
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
||||||
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.rlbAlias
|
import org.gotson.komga.infrastructure.jooq.rlbAlias
|
||||||
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
||||||
|
|
@ -30,10 +31,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class BookDao(
|
class BookDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : BookRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
BookRepository {
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import org.gotson.komga.domain.model.SearchContext
|
||||||
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
||||||
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
||||||
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.noCase
|
import org.gotson.komga.infrastructure.jooq.noCase
|
||||||
|
|
@ -51,11 +52,13 @@ import java.net.URL
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class BookDtoDao(
|
class BookDtoDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val luceneHelper: LuceneHelper,
|
private val luceneHelper: LuceneHelper,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
private val bookCommonDao: BookCommonDao,
|
private val bookCommonDao: BookCommonDao,
|
||||||
) : BookDtoRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
BookDtoRepository {
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Author
|
import org.gotson.komga.domain.model.Author
|
||||||
import org.gotson.komga.domain.model.BookMetadataAggregation
|
import org.gotson.komga.domain.model.BookMetadataAggregation
|
||||||
import org.gotson.komga.domain.persistence.BookMetadataAggregationRepository
|
import org.gotson.komga.domain.persistence.BookMetadataAggregationRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationAuthorRecord
|
import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationAuthorRecord
|
||||||
|
|
@ -18,10 +19,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class BookMetadataAggregationDao(
|
class BookMetadataAggregationDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : BookMetadataAggregationRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
BookMetadataAggregationRepository {
|
||||||
private val d = Tables.BOOK_METADATA_AGGREGATION
|
private val d = Tables.BOOK_METADATA_AGGREGATION
|
||||||
private val a = Tables.BOOK_METADATA_AGGREGATION_AUTHOR
|
private val a = Tables.BOOK_METADATA_AGGREGATION_AUTHOR
|
||||||
private val t = Tables.BOOK_METADATA_AGGREGATION_TAG
|
private val t = Tables.BOOK_METADATA_AGGREGATION_TAG
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.Author
|
||||||
import org.gotson.komga.domain.model.BookMetadata
|
import org.gotson.komga.domain.model.BookMetadata
|
||||||
import org.gotson.komga.domain.model.WebLink
|
import org.gotson.komga.domain.model.WebLink
|
||||||
import org.gotson.komga.domain.persistence.BookMetadataRepository
|
import org.gotson.komga.domain.persistence.BookMetadataRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.BookMetadataAuthorRecord
|
import org.gotson.komga.jooq.main.tables.records.BookMetadataAuthorRecord
|
||||||
|
|
@ -20,10 +21,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class BookMetadataDao(
|
class BookMetadataDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : BookMetadataRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
BookMetadataRepository {
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
private val a = Tables.BOOK_METADATA_AUTHOR
|
private val a = Tables.BOOK_METADATA_AUTHOR
|
||||||
private val bt = Tables.BOOK_METADATA_TAG
|
private val bt = Tables.BOOK_METADATA_TAG
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gotson.komga.infrastructure.jooq.main
|
package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.interfaces.api.rest.dto.ClientSettingDto
|
import org.gotson.komga.interfaces.api.rest.dto.ClientSettingDto
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -8,9 +9,9 @@ import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ClientSettingsDtoDao(
|
class ClientSettingsDtoDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) {
|
) : SplitDslDaoBase(dslRW, dslRO) {
|
||||||
private val g = Tables.CLIENT_SETTINGS_GLOBAL
|
private val g = Tables.CLIENT_SETTINGS_GLOBAL
|
||||||
private val u = Tables.CLIENT_SETTINGS_USER
|
private val u = Tables.CLIENT_SETTINGS_USER
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gotson.komga.infrastructure.jooq.main
|
package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
||||||
import org.gotson.komga.interfaces.api.persistence.HistoricalEventDtoRepository
|
import org.gotson.komga.interfaces.api.persistence.HistoricalEventDtoRepository
|
||||||
import org.gotson.komga.interfaces.api.rest.dto.HistoricalEventDto
|
import org.gotson.komga.interfaces.api.rest.dto.HistoricalEventDto
|
||||||
|
|
@ -15,8 +16,10 @@ import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class HistoricalEventDtoDao(
|
class HistoricalEventDtoDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
) : HistoricalEventDtoRepository {
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
HistoricalEventDtoRepository {
|
||||||
private val e = Tables.HISTORICAL_EVENT
|
private val e = Tables.HISTORICAL_EVENT
|
||||||
private val ep = Tables.HISTORICAL_EVENT_PROPERTIES
|
private val ep = Tables.HISTORICAL_EVENT_PROPERTIES
|
||||||
|
|
||||||
|
|
@ -41,6 +44,7 @@ class HistoricalEventDtoDao(
|
||||||
.map { er ->
|
.map { er ->
|
||||||
val epr = dslRO.selectFrom(ep).where(ep.ID.eq(er.id)).fetch()
|
val epr = dslRO.selectFrom(ep).where(ep.ID.eq(er.id)).fetch()
|
||||||
HistoricalEventDto(
|
HistoricalEventDto(
|
||||||
|
id = er.id,
|
||||||
type = er.type,
|
type = er.type,
|
||||||
timestamp = er.timestamp,
|
timestamp = er.timestamp,
|
||||||
bookId = er.bookId,
|
bookId = er.bookId,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import org.gotson.komga.domain.model.MediaExtensionEpub
|
import org.gotson.komga.domain.model.MediaExtensionEpub
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.deserializeMediaExtension
|
import org.gotson.komga.infrastructure.jooq.deserializeMediaExtension
|
||||||
import org.gotson.komga.interfaces.api.kobo.dto.ContributorDto
|
import org.gotson.komga.interfaces.api.kobo.dto.ContributorDto
|
||||||
import org.gotson.komga.interfaces.api.kobo.dto.KoboBookMetadataDto
|
import org.gotson.komga.interfaces.api.kobo.dto.KoboBookMetadataDto
|
||||||
|
|
@ -16,9 +17,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class KoboDtoDao(
|
class KoboDtoDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val mapper: ObjectMapper,
|
private val mapper: ObjectMapper,
|
||||||
) : KoboDtoRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
KoboDtoRepository {
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import org.gotson.komga.domain.model.ContentRestrictions
|
||||||
import org.gotson.komga.domain.model.KomgaUser
|
import org.gotson.komga.domain.model.KomgaUser
|
||||||
import org.gotson.komga.domain.model.UserRoles
|
import org.gotson.komga.domain.model.UserRoles
|
||||||
import org.gotson.komga.domain.persistence.KomgaUserRepository
|
import org.gotson.komga.domain.persistence.KomgaUserRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.UserApiKeyRecord
|
import org.gotson.komga.jooq.main.tables.records.UserApiKeyRecord
|
||||||
import org.gotson.komga.language.toCurrentTimeZone
|
import org.gotson.komga.language.toCurrentTimeZone
|
||||||
|
|
@ -21,9 +22,10 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class KomgaUserDao(
|
class KomgaUserDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : KomgaUserRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
KomgaUserRepository {
|
||||||
private val u = Tables.USER
|
private val u = Tables.USER
|
||||||
private val ur = Tables.USER_ROLE
|
private val ur = Tables.USER_ROLE
|
||||||
private val ul = Tables.USER_LIBRARY_SHARING
|
private val ul = Tables.USER_LIBRARY_SHARING
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
import org.gotson.komga.domain.model.Library
|
import org.gotson.komga.domain.model.Library
|
||||||
import org.gotson.komga.domain.persistence.LibraryRepository
|
import org.gotson.komga.domain.persistence.LibraryRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.LibraryRecord
|
import org.gotson.komga.jooq.main.tables.records.LibraryRecord
|
||||||
import org.gotson.komga.language.toCurrentTimeZone
|
import org.gotson.komga.language.toCurrentTimeZone
|
||||||
|
|
@ -17,9 +18,10 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class LibraryDao(
|
class LibraryDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : LibraryRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
LibraryRepository {
|
||||||
private val l = Tables.LIBRARY
|
private val l = Tables.LIBRARY
|
||||||
private val ul = Tables.USER_LIBRARY_SHARING
|
private val ul = Tables.USER_LIBRARY_SHARING
|
||||||
private val le = Tables.LIBRARY_EXCLUSIONS
|
private val le = Tables.LIBRARY_EXCLUSIONS
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import org.gotson.komga.domain.model.MediaExtension
|
||||||
import org.gotson.komga.domain.model.MediaFile
|
import org.gotson.komga.domain.model.MediaFile
|
||||||
import org.gotson.komga.domain.model.ProxyExtension
|
import org.gotson.komga.domain.model.ProxyExtension
|
||||||
import org.gotson.komga.domain.persistence.MediaRepository
|
import org.gotson.komga.domain.persistence.MediaRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.deserializeMediaExtension
|
import org.gotson.komga.infrastructure.jooq.deserializeMediaExtension
|
||||||
import org.gotson.komga.infrastructure.jooq.serializeJsonGz
|
import org.gotson.komga.infrastructure.jooq.serializeJsonGz
|
||||||
|
|
@ -27,11 +28,12 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class MediaDao(
|
class MediaDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
private val mapper: ObjectMapper,
|
private val mapper: ObjectMapper,
|
||||||
) : MediaRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
MediaRepository {
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val p = Tables.MEDIA_PAGE
|
private val p = Tables.MEDIA_PAGE
|
||||||
private val f = Tables.MEDIA_FILE
|
private val f = Tables.MEDIA_FILE
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.gotson.komga.domain.model.PageHashKnown
|
||||||
import org.gotson.komga.domain.model.PageHashMatch
|
import org.gotson.komga.domain.model.PageHashMatch
|
||||||
import org.gotson.komga.domain.model.PageHashUnknown
|
import org.gotson.komga.domain.model.PageHashUnknown
|
||||||
import org.gotson.komga.domain.persistence.PageHashRepository
|
import org.gotson.komga.domain.persistence.PageHashRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
import org.gotson.komga.infrastructure.jooq.toOrderBy
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.PageHashRecord
|
import org.gotson.komga.jooq.main.tables.records.PageHashRecord
|
||||||
|
|
@ -25,9 +26,10 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class PageHashDao(
|
class PageHashDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : PageHashRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
PageHashRepository {
|
||||||
private val p = Tables.MEDIA_PAGE
|
private val p = Tables.MEDIA_PAGE
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val ph = Tables.PAGE_HASH
|
private val ph = Tables.PAGE_HASH
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.ContentRestrictions
|
||||||
import org.gotson.komga.domain.model.ReadList
|
import org.gotson.komga.domain.model.ReadList
|
||||||
import org.gotson.komga.domain.persistence.ReadListRepository
|
import org.gotson.komga.domain.persistence.ReadListRepository
|
||||||
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
||||||
import org.gotson.komga.infrastructure.jooq.sortByValues
|
import org.gotson.komga.infrastructure.jooq.sortByValues
|
||||||
|
|
@ -32,11 +33,12 @@ import java.util.SortedMap
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ReadListDao(
|
class ReadListDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val luceneHelper: LuceneHelper,
|
private val luceneHelper: LuceneHelper,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : ReadListRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ReadListRepository {
|
||||||
private val rl = Tables.READLIST
|
private val rl = Tables.READLIST
|
||||||
private val rlb = Tables.READLIST_BOOK
|
private val rlb = Tables.READLIST_BOOK
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.gotson.komga.domain.model.ReadListRequestBookMatchBook
|
||||||
import org.gotson.komga.domain.model.ReadListRequestBookMatchSeries
|
import org.gotson.komga.domain.model.ReadListRequestBookMatchSeries
|
||||||
import org.gotson.komga.domain.model.ReadListRequestBookMatches
|
import org.gotson.komga.domain.model.ReadListRequestBookMatches
|
||||||
import org.gotson.komga.domain.persistence.ReadListRequestRepository
|
import org.gotson.komga.domain.persistence.ReadListRequestRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.noCase
|
import org.gotson.komga.infrastructure.jooq.noCase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -18,8 +19,10 @@ import java.time.LocalDate
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ReadListRequestDao(
|
class ReadListRequestDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
) : ReadListRequestRepository {
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ReadListRequestRepository {
|
||||||
private val sd = Tables.SERIES_METADATA
|
private val sd = Tables.SERIES_METADATA
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val bd = Tables.BOOK_METADATA
|
private val bd = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import org.gotson.komga.domain.model.R2Locator
|
import org.gotson.komga.domain.model.R2Locator
|
||||||
import org.gotson.komga.domain.model.ReadProgress
|
import org.gotson.komga.domain.model.ReadProgress
|
||||||
import org.gotson.komga.domain.persistence.ReadProgressRepository
|
import org.gotson.komga.domain.persistence.ReadProgressRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.deserializeJsonGz
|
import org.gotson.komga.infrastructure.jooq.deserializeJsonGz
|
||||||
|
|
@ -24,11 +25,12 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ReadProgressDao(
|
class ReadProgressDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
private val mapper: ObjectMapper,
|
private val mapper: ObjectMapper,
|
||||||
) : ReadProgressRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ReadProgressRepository {
|
||||||
private val r = Tables.READ_PROGRESS
|
private val r = Tables.READ_PROGRESS
|
||||||
private val rs = Tables.READ_PROGRESS_SERIES
|
private val rs = Tables.READ_PROGRESS_SERIES
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gotson.komga.infrastructure.jooq.main
|
package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.interfaces.api.persistence.ReadProgressDtoRepository
|
import org.gotson.komga.interfaces.api.persistence.ReadProgressDtoRepository
|
||||||
import org.gotson.komga.interfaces.api.rest.dto.TachiyomiReadProgressDto
|
import org.gotson.komga.interfaces.api.rest.dto.TachiyomiReadProgressDto
|
||||||
import org.gotson.komga.interfaces.api.rest.dto.TachiyomiReadProgressV2Dto
|
import org.gotson.komga.interfaces.api.rest.dto.TachiyomiReadProgressV2Dto
|
||||||
|
|
@ -16,8 +17,10 @@ import java.math.BigDecimal
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ReadProgressDtoDao(
|
class ReadProgressDtoDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
) : ReadProgressDtoRepository {
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ReadProgressDtoRepository {
|
||||||
private val rlb = Tables.READLIST_BOOK
|
private val rlb = Tables.READLIST_BOOK
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Author
|
import org.gotson.komga.domain.model.Author
|
||||||
import org.gotson.komga.domain.persistence.ReferentialRepository
|
import org.gotson.komga.domain.persistence.ReferentialRepository
|
||||||
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.udfStripAccents
|
import org.gotson.komga.infrastructure.jooq.udfStripAccents
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationAuthorRecord
|
import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationAuthorRecord
|
||||||
|
|
@ -22,8 +23,10 @@ import java.time.LocalDate
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ReferentialDao(
|
class ReferentialDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
) : ReferentialRepository {
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ReferentialRepository {
|
||||||
private val a = Tables.BOOK_METADATA_AUTHOR
|
private val a = Tables.BOOK_METADATA_AUTHOR
|
||||||
private val sd = Tables.SERIES_METADATA
|
private val sd = Tables.SERIES_METADATA
|
||||||
private val bma = Tables.BOOK_METADATA_AGGREGATION
|
private val bma = Tables.BOOK_METADATA_AGGREGATION
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.ContentRestrictions
|
||||||
import org.gotson.komga.domain.model.SeriesCollection
|
import org.gotson.komga.domain.model.SeriesCollection
|
||||||
import org.gotson.komga.domain.persistence.SeriesCollectionRepository
|
import org.gotson.komga.domain.persistence.SeriesCollectionRepository
|
||||||
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
||||||
import org.gotson.komga.infrastructure.jooq.sortByValues
|
import org.gotson.komga.infrastructure.jooq.sortByValues
|
||||||
|
|
@ -31,11 +32,12 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SeriesCollectionDao(
|
class SeriesCollectionDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val luceneHelper: LuceneHelper,
|
private val luceneHelper: LuceneHelper,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : SeriesCollectionRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SeriesCollectionRepository {
|
||||||
private val c = Tables.COLLECTION
|
private val c = Tables.COLLECTION
|
||||||
private val cs = Tables.COLLECTION_SERIES
|
private val cs = Tables.COLLECTION_SERIES
|
||||||
private val s = Tables.SERIES
|
private val s = Tables.SERIES
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import org.gotson.komga.domain.model.Series
|
||||||
import org.gotson.komga.domain.persistence.SeriesRepository
|
import org.gotson.komga.domain.persistence.SeriesRepository
|
||||||
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
||||||
import org.gotson.komga.infrastructure.jooq.SeriesSearchHelper
|
import org.gotson.komga.infrastructure.jooq.SeriesSearchHelper
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.csAlias
|
import org.gotson.komga.infrastructure.jooq.csAlias
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
|
|
@ -28,10 +29,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SeriesDao(
|
class SeriesDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : SeriesRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SeriesRepository {
|
||||||
private val s = Tables.SERIES
|
private val s = Tables.SERIES
|
||||||
private val d = Tables.SERIES_METADATA
|
private val d = Tables.SERIES_METADATA
|
||||||
private val rs = Tables.READ_PROGRESS_SERIES
|
private val rs = Tables.READ_PROGRESS_SERIES
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import org.gotson.komga.domain.model.SeriesSearch
|
||||||
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
import org.gotson.komga.infrastructure.datasource.SqliteUdfDataSource
|
||||||
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
||||||
import org.gotson.komga.infrastructure.jooq.SeriesSearchHelper
|
import org.gotson.komga.infrastructure.jooq.SeriesSearchHelper
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.infrastructure.jooq.csAlias
|
import org.gotson.komga.infrastructure.jooq.csAlias
|
||||||
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
||||||
|
|
@ -52,10 +53,12 @@ const val BOOKS_READ_COUNT = "booksReadCount"
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SeriesDtoDao(
|
class SeriesDtoDao(
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
dslRW: DSLContext,
|
||||||
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val luceneHelper: LuceneHelper,
|
private val luceneHelper: LuceneHelper,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : SeriesDtoRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SeriesDtoRepository {
|
||||||
private val s = Tables.SERIES
|
private val s = Tables.SERIES
|
||||||
private val d = Tables.SERIES_METADATA
|
private val d = Tables.SERIES_METADATA
|
||||||
private val rs = Tables.READ_PROGRESS_SERIES
|
private val rs = Tables.READ_PROGRESS_SERIES
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.AlternateTitle
|
||||||
import org.gotson.komga.domain.model.SeriesMetadata
|
import org.gotson.komga.domain.model.SeriesMetadata
|
||||||
import org.gotson.komga.domain.model.WebLink
|
import org.gotson.komga.domain.model.WebLink
|
||||||
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
|
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.SeriesMetadataRecord
|
import org.gotson.komga.jooq.main.tables.records.SeriesMetadataRecord
|
||||||
|
|
@ -19,10 +20,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SeriesMetadataDao(
|
class SeriesMetadataDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : SeriesMetadataRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SeriesMetadataRepository {
|
||||||
private val d = Tables.SERIES_METADATA
|
private val d = Tables.SERIES_METADATA
|
||||||
private val g = Tables.SERIES_METADATA_GENRE
|
private val g = Tables.SERIES_METADATA_GENRE
|
||||||
private val st = Tables.SERIES_METADATA_TAG
|
private val st = Tables.SERIES_METADATA_TAG
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gotson.komga.infrastructure.jooq.main
|
package org.gotson.komga.infrastructure.jooq.main
|
||||||
|
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
|
@ -7,9 +8,9 @@ import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ServerSettingsDao(
|
class ServerSettingsDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) {
|
) : SplitDslDaoBase(dslRW, dslRO) {
|
||||||
private val s = Tables.SERVER_SETTINGS
|
private val s = Tables.SERVER_SETTINGS
|
||||||
|
|
||||||
fun <T> getSettingByKey(
|
fun <T> getSettingByKey(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Sidecar
|
import org.gotson.komga.domain.model.Sidecar
|
||||||
import org.gotson.komga.domain.model.SidecarStored
|
import org.gotson.komga.domain.model.SidecarStored
|
||||||
import org.gotson.komga.domain.persistence.SidecarRepository
|
import org.gotson.komga.domain.persistence.SidecarRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.SidecarRecord
|
import org.gotson.komga.jooq.main.tables.records.SidecarRecord
|
||||||
|
|
@ -16,10 +17,11 @@ import java.net.URL
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SidecarDao(
|
class SidecarDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : SidecarRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SidecarRepository {
|
||||||
private val sc = Tables.SIDECAR
|
private val sc = Tables.SIDECAR
|
||||||
|
|
||||||
override fun findAll(): Collection<SidecarStored> = dslRO.selectFrom(sc).fetch().map { it.toDomain() }
|
override fun findAll(): Collection<SidecarStored> = dslRO.selectFrom(sc).fetch().map { it.toDomain() }
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import org.gotson.komga.domain.model.SyncPoint.ReadList.Companion.ON_DECK_ID
|
||||||
import org.gotson.komga.domain.persistence.SyncPointRepository
|
import org.gotson.komga.domain.persistence.SyncPointRepository
|
||||||
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
import org.gotson.komga.infrastructure.jooq.BookSearchHelper
|
||||||
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
import org.gotson.komga.infrastructure.jooq.RequiredJoin
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.language.toZonedDateTime
|
import org.gotson.komga.language.toZonedDateTime
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -28,10 +29,11 @@ import java.time.ZoneId
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class SyncPointDao(
|
class SyncPointDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
private val bookCommonDao: BookCommonDao,
|
private val bookCommonDao: BookCommonDao,
|
||||||
) : SyncPointRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
SyncPointRepository {
|
||||||
private val b = Tables.BOOK
|
private val b = Tables.BOOK
|
||||||
private val m = Tables.MEDIA
|
private val m = Tables.MEDIA
|
||||||
private val d = Tables.BOOK_METADATA
|
private val d = Tables.BOOK_METADATA
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Dimension
|
import org.gotson.komga.domain.model.Dimension
|
||||||
import org.gotson.komga.domain.model.ThumbnailBook
|
import org.gotson.komga.domain.model.ThumbnailBook
|
||||||
import org.gotson.komga.domain.persistence.ThumbnailBookRepository
|
import org.gotson.komga.domain.persistence.ThumbnailBookRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.ThumbnailBookRecord
|
import org.gotson.komga.jooq.main.tables.records.ThumbnailBookRecord
|
||||||
|
|
@ -15,10 +16,11 @@ import java.net.URL
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ThumbnailBookDao(
|
class ThumbnailBookDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : ThumbnailBookRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ThumbnailBookRepository {
|
||||||
private val tb = Tables.THUMBNAIL_BOOK
|
private val tb = Tables.THUMBNAIL_BOOK
|
||||||
|
|
||||||
override fun findAllByBookId(bookId: String): Collection<ThumbnailBook> =
|
override fun findAllByBookId(bookId: String): Collection<ThumbnailBook> =
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Dimension
|
import org.gotson.komga.domain.model.Dimension
|
||||||
import org.gotson.komga.domain.model.ThumbnailReadList
|
import org.gotson.komga.domain.model.ThumbnailReadList
|
||||||
import org.gotson.komga.domain.persistence.ThumbnailReadListRepository
|
import org.gotson.komga.domain.persistence.ThumbnailReadListRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.ThumbnailReadlistRecord
|
import org.gotson.komga.jooq.main.tables.records.ThumbnailReadlistRecord
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -12,9 +13,10 @@ import org.springframework.transaction.annotation.Transactional
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ThumbnailReadListDao(
|
class ThumbnailReadListDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : ThumbnailReadListRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ThumbnailReadListRepository {
|
||||||
private val tr = Tables.THUMBNAIL_READLIST
|
private val tr = Tables.THUMBNAIL_READLIST
|
||||||
|
|
||||||
override fun findAllByReadListId(readListId: String): Collection<ThumbnailReadList> =
|
override fun findAllByReadListId(readListId: String): Collection<ThumbnailReadList> =
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Dimension
|
import org.gotson.komga.domain.model.Dimension
|
||||||
import org.gotson.komga.domain.model.ThumbnailSeriesCollection
|
import org.gotson.komga.domain.model.ThumbnailSeriesCollection
|
||||||
import org.gotson.komga.domain.persistence.ThumbnailSeriesCollectionRepository
|
import org.gotson.komga.domain.persistence.ThumbnailSeriesCollectionRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.ThumbnailCollectionRecord
|
import org.gotson.komga.jooq.main.tables.records.ThumbnailCollectionRecord
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
|
|
@ -12,9 +13,10 @@ import org.springframework.transaction.annotation.Transactional
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ThumbnailSeriesCollectionDao(
|
class ThumbnailSeriesCollectionDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
) : ThumbnailSeriesCollectionRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ThumbnailSeriesCollectionRepository {
|
||||||
private val tc = Tables.THUMBNAIL_COLLECTION
|
private val tc = Tables.THUMBNAIL_COLLECTION
|
||||||
|
|
||||||
override fun findByIdOrNull(thumbnailId: String): ThumbnailSeriesCollection? =
|
override fun findByIdOrNull(thumbnailId: String): ThumbnailSeriesCollection? =
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.jooq.main
|
||||||
import org.gotson.komga.domain.model.Dimension
|
import org.gotson.komga.domain.model.Dimension
|
||||||
import org.gotson.komga.domain.model.ThumbnailSeries
|
import org.gotson.komga.domain.model.ThumbnailSeries
|
||||||
import org.gotson.komga.domain.persistence.ThumbnailSeriesRepository
|
import org.gotson.komga.domain.persistence.ThumbnailSeriesRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable
|
||||||
import org.gotson.komga.jooq.main.Tables
|
import org.gotson.komga.jooq.main.Tables
|
||||||
import org.gotson.komga.jooq.main.tables.records.ThumbnailSeriesRecord
|
import org.gotson.komga.jooq.main.tables.records.ThumbnailSeriesRecord
|
||||||
|
|
@ -15,10 +16,11 @@ import java.net.URL
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ThumbnailSeriesDao(
|
class ThumbnailSeriesDao(
|
||||||
private val dslRW: DSLContext,
|
dslRW: DSLContext,
|
||||||
@Qualifier("dslContextRO") private val dslRO: DSLContext,
|
@Qualifier("dslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||||
) : ThumbnailSeriesRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
ThumbnailSeriesRepository {
|
||||||
private val ts = Tables.THUMBNAIL_SERIES
|
private val ts = Tables.THUMBNAIL_SERIES
|
||||||
|
|
||||||
override fun findByIdOrNull(thumbnailId: String): ThumbnailSeries? =
|
override fun findByIdOrNull(thumbnailId: String): ThumbnailSeries? =
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import org.gotson.komga.application.tasks.Task
|
import org.gotson.komga.application.tasks.Task
|
||||||
import org.gotson.komga.application.tasks.TasksRepository
|
import org.gotson.komga.application.tasks.TasksRepository
|
||||||
|
import org.gotson.komga.infrastructure.jooq.SplitDslDaoBase
|
||||||
import org.gotson.komga.jooq.tasks.Tables
|
import org.gotson.komga.jooq.tasks.Tables
|
||||||
import org.jooq.DSLContext
|
import org.jooq.DSLContext
|
||||||
import org.jooq.Query
|
import org.jooq.Query
|
||||||
|
|
@ -22,11 +23,12 @@ private val logger = KotlinLogging.logger {}
|
||||||
@Component
|
@Component
|
||||||
@DependsOn("flywaySecondaryMigrationInitializer")
|
@DependsOn("flywaySecondaryMigrationInitializer")
|
||||||
class TasksDao(
|
class TasksDao(
|
||||||
@Qualifier("tasksDslContextRW") private val dslRW: DSLContext,
|
@Qualifier("tasksDslContextRW") dslRW: DSLContext,
|
||||||
@Qualifier("tasksDslContextRO") private val dslRO: DSLContext,
|
@Qualifier("tasksDslContextRO") dslRO: DSLContext,
|
||||||
@param:Value("#{@komgaProperties.tasksDb.batchChunkSize}") private val batchSize: Int,
|
@param:Value("#{@komgaProperties.tasksDb.batchChunkSize}") private val batchSize: Int,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
) : TasksRepository {
|
) : SplitDslDaoBase(dslRW, dslRO),
|
||||||
|
TasksRepository {
|
||||||
private val t = Tables.TASK
|
private val t = Tables.TASK
|
||||||
|
|
||||||
private val tasksAvailableCondition =
|
private val tasksAvailableCondition =
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import org.springframework.util.LinkedMultiValueMap
|
||||||
import org.springframework.web.client.RestClient
|
import org.springframework.web.client.RestClient
|
||||||
import org.springframework.web.client.toEntity
|
import org.springframework.web.client.toEntity
|
||||||
import org.springframework.web.server.ResponseStatusException
|
import org.springframework.web.server.ResponseStatusException
|
||||||
|
import org.springframework.web.util.DefaultUriBuilderFactory
|
||||||
import kotlin.time.Duration.Companion.minutes
|
import kotlin.time.Duration.Companion.minutes
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
|
|
||||||
|
|
@ -29,11 +30,15 @@ class KoboProxy(
|
||||||
private val komgaSyncTokenGenerator: KomgaSyncTokenGenerator,
|
private val komgaSyncTokenGenerator: KomgaSyncTokenGenerator,
|
||||||
private val komgaSettingsProvider: KomgaSettingsProvider,
|
private val komgaSettingsProvider: KomgaSettingsProvider,
|
||||||
) {
|
) {
|
||||||
private val koboApiClient =
|
private val koboApiClient: RestClient =
|
||||||
RestClient
|
RestClient
|
||||||
.builder()
|
.builder()
|
||||||
.baseUrl("https://storeapi.kobo.com")
|
.uriBuilderFactory(
|
||||||
.requestFactory(
|
DefaultUriBuilderFactory("https://storeapi.kobo.com")
|
||||||
|
.apply {
|
||||||
|
this.encodingMode = DefaultUriBuilderFactory.EncodingMode.NONE
|
||||||
|
},
|
||||||
|
).requestFactory(
|
||||||
ClientHttpRequestFactoryBuilder.reactor().build(
|
ClientHttpRequestFactoryBuilder.reactor().build(
|
||||||
ClientHttpRequestFactorySettings
|
ClientHttpRequestFactorySettings
|
||||||
.defaults()
|
.defaults()
|
||||||
|
|
@ -42,7 +47,7 @@ class KoboProxy(
|
||||||
),
|
),
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
private val pathRegex = """\/kobo\/[-\w]*(.*)""".toRegex()
|
private val pathRegex = """/kobo/[-\w]*(.*)""".toRegex()
|
||||||
|
|
||||||
private val headersOutInclude =
|
private val headersOutInclude =
|
||||||
setOf(
|
setOf(
|
||||||
|
|
@ -50,6 +55,7 @@ class KoboProxy(
|
||||||
HttpHeaders.USER_AGENT,
|
HttpHeaders.USER_AGENT,
|
||||||
HttpHeaders.ACCEPT,
|
HttpHeaders.ACCEPT,
|
||||||
HttpHeaders.ACCEPT_LANGUAGE,
|
HttpHeaders.ACCEPT_LANGUAGE,
|
||||||
|
HttpHeaders.CONTENT_TYPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val headersOutExclude =
|
private val headersOutExclude =
|
||||||
|
|
@ -88,7 +94,7 @@ class KoboProxy(
|
||||||
.uri { uriBuilder ->
|
.uri { uriBuilder ->
|
||||||
uriBuilder
|
uriBuilder
|
||||||
.path(path)
|
.path(path)
|
||||||
.queryParams(LinkedMultiValueMap(request.parameterMap.mapValues { it.value.toList() }))
|
.query(request.queryString)
|
||||||
.build()
|
.build()
|
||||||
.also { logger.debug { "Proxy URL: $it" } }
|
.also { logger.debug { "Proxy URL: $it" } }
|
||||||
}.headers { headersOut ->
|
}.headers { headersOut ->
|
||||||
|
|
@ -110,6 +116,7 @@ class KoboProxy(
|
||||||
}.apply { if (body != null) body(body) }
|
}.apply { if (body != null) body(body) }
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.onStatus(HttpStatusCode::isError) { _, response ->
|
.onStatus(HttpStatusCode::isError) { _, response ->
|
||||||
|
logger.debug { "Kobo response: ${response.statusCode}: ${response.body.bufferedReader().use { it.readText() }}" }
|
||||||
throw ResponseStatusException(response.statusCode, response.statusText)
|
throw ResponseStatusException(response.statusCode, response.statusText)
|
||||||
}.toEntity<JsonNode>()
|
}.toEntity<JsonNode>()
|
||||||
|
|
||||||
|
|
@ -161,6 +168,7 @@ class KoboProxy(
|
||||||
"audiobook_subscription_tiers": "https://www.kobo.com/{region}/{language}/checkoutoption/21C6D938-934B-4A91-B979-E14D70B2F280",
|
"audiobook_subscription_tiers": "https://www.kobo.com/{region}/{language}/checkoutoption/21C6D938-934B-4A91-B979-E14D70B2F280",
|
||||||
"authorproduct_recommendations": "https://storeapi.kobo.com/v1/products/books/authors/recommendations",
|
"authorproduct_recommendations": "https://storeapi.kobo.com/v1/products/books/authors/recommendations",
|
||||||
"autocomplete": "https://storeapi.kobo.com/v1/products/autocomplete",
|
"autocomplete": "https://storeapi.kobo.com/v1/products/autocomplete",
|
||||||
|
"bam": "https://storeapi.kobo.com/v2/activity/bam/success",
|
||||||
"blackstone_header": {
|
"blackstone_header": {
|
||||||
"key": "x-amz-request-payer",
|
"key": "x-amz-request-payer",
|
||||||
"value": "requester"
|
"value": "requester"
|
||||||
|
|
@ -173,6 +181,7 @@ class KoboProxy(
|
||||||
"browse_history": "https://storeapi.kobo.com/v1/user/browsehistory",
|
"browse_history": "https://storeapi.kobo.com/v1/user/browsehistory",
|
||||||
"categories": "https://storeapi.kobo.com/v1/categories",
|
"categories": "https://storeapi.kobo.com/v1/categories",
|
||||||
"categories_page": "https://www.kobo.com/ebooks/categories",
|
"categories_page": "https://www.kobo.com/ebooks/categories",
|
||||||
|
"categoriesv2": "https://storeapi.kobo.com/api/v2/Categories/Top",
|
||||||
"category": "https://storeapi.kobo.com/v1/categories/{CategoryId}",
|
"category": "https://storeapi.kobo.com/v1/categories/{CategoryId}",
|
||||||
"category_featured_lists": "https://storeapi.kobo.com/v1/categories/{CategoryId}/featured",
|
"category_featured_lists": "https://storeapi.kobo.com/v1/categories/{CategoryId}/featured",
|
||||||
"category_products": "https://storeapi.kobo.com/v1/categories/{CategoryId}/products",
|
"category_products": "https://storeapi.kobo.com/v1/categories/{CategoryId}/products",
|
||||||
|
|
@ -180,6 +189,7 @@ class KoboProxy(
|
||||||
"client_authd_referral": "https://authorize.kobo.com/api/AuthenticatedReferral/client/v1/getLink",
|
"client_authd_referral": "https://authorize.kobo.com/api/AuthenticatedReferral/client/v1/getLink",
|
||||||
"configuration_data": "https://storeapi.kobo.com/v1/configuration",
|
"configuration_data": "https://storeapi.kobo.com/v1/configuration",
|
||||||
"content_access_book": "https://storeapi.kobo.com/v1/products/books/{ProductId}/access",
|
"content_access_book": "https://storeapi.kobo.com/v1/products/books/{ProductId}/access",
|
||||||
|
"contributorsv2": "https://storeapi.kobo.com/v2/contributors/author",
|
||||||
"customer_care_live_chat": "https://v2.zopim.com/widget/livechat.html?key=Y6gwUmnu4OATxN3Tli4Av9bYN319BTdO",
|
"customer_care_live_chat": "https://v2.zopim.com/widget/livechat.html?key=Y6gwUmnu4OATxN3Tli4Av9bYN319BTdO",
|
||||||
"daily_deal": "https://storeapi.kobo.com/v1/products/dailydeal",
|
"daily_deal": "https://storeapi.kobo.com/v1/products/dailydeal",
|
||||||
"deals": "https://storeapi.kobo.com/v1/deals",
|
"deals": "https://storeapi.kobo.com/v1/deals",
|
||||||
|
|
@ -190,14 +200,19 @@ class KoboProxy(
|
||||||
"device_refresh": "https://storeapi.kobo.com/v1/auth/refresh",
|
"device_refresh": "https://storeapi.kobo.com/v1/auth/refresh",
|
||||||
"dictionary_host": "https://ereaderfiles.kobo.com",
|
"dictionary_host": "https://ereaderfiles.kobo.com",
|
||||||
"discovery_host": "https://discovery.kobobooks.com",
|
"discovery_host": "https://discovery.kobobooks.com",
|
||||||
|
"display_accessibility_enabled": "False",
|
||||||
|
"display_parental_controls_enabled": "True",
|
||||||
"dropbox_link_account_poll": "https://authorize.kobo.com/{region}/{language}/LinkDropbox",
|
"dropbox_link_account_poll": "https://authorize.kobo.com/{region}/{language}/LinkDropbox",
|
||||||
"dropbox_link_account_start": "https://authorize.kobo.com/LinkDropbox/start",
|
"dropbox_link_account_start": "https://authorize.kobo.com/LinkDropbox/start",
|
||||||
|
"ereaderdevices": "https://storeapi.kobo.com/v2/products/EReaderDeviceFeeds",
|
||||||
"eula_page": "https://www.kobo.com/termsofuse?style=onestore",
|
"eula_page": "https://www.kobo.com/termsofuse?style=onestore",
|
||||||
"exchange_auth": "https://storeapi.kobo.com/v1/auth/exchange",
|
"exchange_auth": "https://storeapi.kobo.com/v1/auth/exchange",
|
||||||
"external_book": "https://storeapi.kobo.com/v1/products/books/external/{Ids}",
|
"external_book": "https://storeapi.kobo.com/v1/products/books/external/{Ids}",
|
||||||
"facebook_sso_page": "https://authorize.kobo.com/signin/provider/Facebook/login?returnUrl=http://kobo.com/",
|
"facebook_sso_page": "https://authorize.kobo.com/signin/provider/Facebook/login?returnUrl=https://kobo.com/",
|
||||||
"featured_list": "https://storeapi.kobo.com/v1/products/featured/{FeaturedListId}",
|
"featured_list": "https://storeapi.kobo.com/v1/products/featured/{FeaturedListId}",
|
||||||
"featured_lists": "https://storeapi.kobo.com/v1/products/featured",
|
"featured_lists": "https://storeapi.kobo.com/v1/products/featured",
|
||||||
|
"featuredlist2": "https://storeapi.kobo.com/v2/products/list/featured",
|
||||||
|
"fixed_layout_page_cache_enabled": "True",
|
||||||
"free_books_page": {
|
"free_books_page": {
|
||||||
"EN": "https://www.kobo.com/{region}/{language}/p/free-ebooks",
|
"EN": "https://www.kobo.com/{region}/{language}/p/free-ebooks",
|
||||||
"FR": "https://www.kobo.com/{region}/{language}/p/livres-gratuits",
|
"FR": "https://www.kobo.com/{region}/{language}/p/livres-gratuits",
|
||||||
|
|
@ -207,6 +222,7 @@ class KoboProxy(
|
||||||
},
|
},
|
||||||
"fte_feedback": "https://storeapi.kobo.com/v1/products/ftefeedback",
|
"fte_feedback": "https://storeapi.kobo.com/v1/products/ftefeedback",
|
||||||
"funnel_metrics": "https://storeapi.kobo.com/v1/funnelmetrics",
|
"funnel_metrics": "https://storeapi.kobo.com/v1/funnelmetrics",
|
||||||
|
"geography_data": "https://storeapi.kobo.com/v2/configuration/geography/country",
|
||||||
"get_download_keys": "https://storeapi.kobo.com/v1/library/downloadkeys",
|
"get_download_keys": "https://storeapi.kobo.com/v1/library/downloadkeys",
|
||||||
"get_download_link": "https://storeapi.kobo.com/v1/library/downloadlink",
|
"get_download_link": "https://storeapi.kobo.com/v1/library/downloadlink",
|
||||||
"get_tests_request": "https://storeapi.kobo.com/v1/analytics/gettests",
|
"get_tests_request": "https://storeapi.kobo.com/v1/analytics/gettests",
|
||||||
|
|
@ -214,10 +230,13 @@ class KoboProxy(
|
||||||
"giftcard_redeem_url": "https://www.kobo.com/{storefront}/{language}/redeem",
|
"giftcard_redeem_url": "https://www.kobo.com/{storefront}/{language}/redeem",
|
||||||
"googledrive_link_account_start": "https://authorize.kobo.com/{region}/{language}/linkcloudstorage/provider/google_drive",
|
"googledrive_link_account_start": "https://authorize.kobo.com/{region}/{language}/linkcloudstorage/provider/google_drive",
|
||||||
"gpb_flow_enabled": "False",
|
"gpb_flow_enabled": "False",
|
||||||
"help_page": "http://www.kobo.com/help",
|
"help_page": "https://www.kobo.com/help",
|
||||||
"image_host": "//cdn.kobo.com/book-images/",
|
"image_host": "//cdn.kobo.com/book-images/",
|
||||||
"image_url_quality_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/{Quality}/{IsGreyscale}/image.jpg",
|
"image_url_quality_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/{Quality}/{IsGreyscale}/image.jpg",
|
||||||
"image_url_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/false/image.jpg",
|
"image_url_template": "https://cdn.kobo.com/book-images/{ImageId}/{Width}/{Height}/false/image.jpg",
|
||||||
|
"instapaper_enabled": "True",
|
||||||
|
"instapaper_env_url": "https://www.instapaper.com/api/kobo",
|
||||||
|
"instapaper_link_account_start": "https://authorize.kobo.com/{region}/{language}/linkinstapaper",
|
||||||
"kobo_audiobooks_credit_redemption": "True",
|
"kobo_audiobooks_credit_redemption": "True",
|
||||||
"kobo_audiobooks_enabled": "True",
|
"kobo_audiobooks_enabled": "True",
|
||||||
"kobo_audiobooks_orange_deal_enabled": "True",
|
"kobo_audiobooks_orange_deal_enabled": "True",
|
||||||
|
|
@ -244,7 +263,8 @@ class KoboProxy(
|
||||||
"love_dashboard_page": "https://www.kobo.com/{region}/{language}/kobosuperpoints",
|
"love_dashboard_page": "https://www.kobo.com/{region}/{language}/kobosuperpoints",
|
||||||
"love_points_redemption_page": "https://www.kobo.com/{region}/{language}/KoboSuperPointsRedemption?productId={ProductId}",
|
"love_points_redemption_page": "https://www.kobo.com/{region}/{language}/KoboSuperPointsRedemption?productId={ProductId}",
|
||||||
"magazine_landing_page": "https://www.kobo.com/emagazines",
|
"magazine_landing_page": "https://www.kobo.com/emagazines",
|
||||||
"more_sign_in_options": "https://authorize.kobo.com/signin?returnUrl=http://kobo.com/#allProviders",
|
"more_sign_in_options": "https://authorize.kobo.com/signin?returnUrl=https://kobo.com/#allProviders",
|
||||||
|
"morebyauthor": "https://storeapi.kobo.com/v2/products/recommendations/morebyauthor",
|
||||||
"notebooks": "https://storeapi.kobo.com/api/internal/notebooks",
|
"notebooks": "https://storeapi.kobo.com/api/internal/notebooks",
|
||||||
"notifications_registration_issue": "https://storeapi.kobo.com/v1/notifications/registration",
|
"notifications_registration_issue": "https://storeapi.kobo.com/v1/notifications/registration",
|
||||||
"oauth_host": "https://oauth.kobo.com",
|
"oauth_host": "https://oauth.kobo.com",
|
||||||
|
|
@ -258,9 +278,13 @@ class KoboProxy(
|
||||||
"product_prices": "https://storeapi.kobo.com/v1/products/{ProductIds}/prices",
|
"product_prices": "https://storeapi.kobo.com/v1/products/{ProductIds}/prices",
|
||||||
"product_recommendations": "https://storeapi.kobo.com/v1/products/{ProductId}/recommendations",
|
"product_recommendations": "https://storeapi.kobo.com/v1/products/{ProductId}/recommendations",
|
||||||
"product_reviews": "https://storeapi.kobo.com/v1/products/{ProductIds}/reviews",
|
"product_reviews": "https://storeapi.kobo.com/v1/products/{ProductIds}/reviews",
|
||||||
|
"productbyid": "https://storeapi.kobo.com/v2/products/itemDetailById/{ProductType}/{Id}",
|
||||||
|
"productbyslug": "https://storeapi.kobo.com/v2/products/itemDetail/{ProductType}/{Slug}",
|
||||||
"products": "https://storeapi.kobo.com/v1/products",
|
"products": "https://storeapi.kobo.com/v1/products",
|
||||||
|
"productstatebyid": "https://storeapi.kobo.com/v2/products/itemStateById/{ProductType}/{Id}",
|
||||||
|
"productstatebyslug": "https://storeapi.kobo.com/v2/products/itemState/{ProductType}/{Slug}",
|
||||||
"productsv2": "https://storeapi.kobo.com/v2/products",
|
"productsv2": "https://storeapi.kobo.com/v2/products",
|
||||||
"provider_external_sign_in_page": "https://authorize.kobo.com/ExternalSignIn/{providerName}?returnUrl=http://kobo.com/",
|
"provider_external_sign_in_page": "https://authorize.kobo.com/ExternalSignIn/{providerName}?returnUrl=https://kobo.com/",
|
||||||
"purchase_buy": "https://www.kobo.com/checkoutoption/",
|
"purchase_buy": "https://www.kobo.com/checkoutoption/",
|
||||||
"purchase_buy_templated": "https://www.kobo.com/{region}/{language}/checkoutoption/{ProductId}",
|
"purchase_buy_templated": "https://www.kobo.com/{region}/{language}/checkoutoption/{ProductId}",
|
||||||
"quickbuy_checkout": "https://storeapi.kobo.com/v1/store/quickbuy/{PurchaseId}/checkout",
|
"quickbuy_checkout": "https://storeapi.kobo.com/v1/store/quickbuy/{PurchaseId}/checkout",
|
||||||
|
|
@ -270,7 +294,9 @@ class KoboProxy(
|
||||||
"reading_services_host": "https://readingservices.kobo.com",
|
"reading_services_host": "https://readingservices.kobo.com",
|
||||||
"reading_state": "https://storeapi.kobo.com/v1/library/{Ids}/state",
|
"reading_state": "https://storeapi.kobo.com/v1/library/{Ids}/state",
|
||||||
"redeem_interstitial_page": "https://www.kobo.com",
|
"redeem_interstitial_page": "https://www.kobo.com",
|
||||||
"registration_page": "https://authorize.kobo.com/signup?returnUrl=http://kobo.com/",
|
"reflowable_page_cache_enabled": "True",
|
||||||
|
"registration_page": "https://authorize.kobo.com/signup?returnUrl=https://kobo.com/",
|
||||||
|
"related": "https://storeapi.kobo.com/v2/products/recommendations/related",
|
||||||
"related_items": "https://storeapi.kobo.com/v1/products/{Id}/related",
|
"related_items": "https://storeapi.kobo.com/v1/products/{Id}/related",
|
||||||
"remaining_book_series": "https://storeapi.kobo.com/v1/products/books/series/{SeriesId}",
|
"remaining_book_series": "https://storeapi.kobo.com/v1/products/books/series/{SeriesId}",
|
||||||
"rename_tag": "https://storeapi.kobo.com/v1/library/tags/{TagId}",
|
"rename_tag": "https://storeapi.kobo.com/v1/library/tags/{TagId}",
|
||||||
|
|
@ -293,14 +319,19 @@ class KoboProxy(
|
||||||
"tags": "https://storeapi.kobo.com/v1/library/tags",
|
"tags": "https://storeapi.kobo.com/v1/library/tags",
|
||||||
"taste_profile": "https://storeapi.kobo.com/v1/products/tasteprofile",
|
"taste_profile": "https://storeapi.kobo.com/v1/products/tasteprofile",
|
||||||
"terms_of_sale_page": "https://authorize.kobo.com/{region}/{language}/terms/termsofsale",
|
"terms_of_sale_page": "https://authorize.kobo.com/{region}/{language}/terms/termsofsale",
|
||||||
|
"topproducts": "https://storeapi.kobo.com/v2/products/list/topproducts",
|
||||||
|
"tracking": "https://storeapi.kobo.com/v2/tracking/searchperformed",
|
||||||
"update_accessibility_to_preview": "https://storeapi.kobo.com/v1/library/{EntitlementIds}/preview",
|
"update_accessibility_to_preview": "https://storeapi.kobo.com/v1/library/{EntitlementIds}/preview",
|
||||||
"use_one_store": "True",
|
"use_one_store": "True",
|
||||||
|
"user_currencyconversion": "https://storeapi.kobo.com/v1/user/currency/convert",
|
||||||
"user_loyalty_benefits": "https://storeapi.kobo.com/v1/user/loyalty/benefits",
|
"user_loyalty_benefits": "https://storeapi.kobo.com/v1/user/loyalty/benefits",
|
||||||
"user_platform": "https://storeapi.kobo.com/v1/user/platform",
|
"user_platform": "https://storeapi.kobo.com/v1/user/platform",
|
||||||
"user_profile": "https://storeapi.kobo.com/v1/user/profile",
|
"user_profile": "https://storeapi.kobo.com/v1/user/profile",
|
||||||
"user_ratings": "https://storeapi.kobo.com/v1/user/ratings",
|
"user_ratings": "https://storeapi.kobo.com/v1/user/ratings",
|
||||||
"user_recommendations": "https://storeapi.kobo.com/v1/user/recommendations",
|
"user_recommendations": "https://storeapi.kobo.com/v1/user/recommendations",
|
||||||
"user_reviews": "https://storeapi.kobo.com/v1/user/reviews",
|
"user_reviews": "https://storeapi.kobo.com/v1/user/reviews",
|
||||||
|
"user_tasteprofile_complete": "https://storeapi.kobo.com/v2/user/tasteprofile/complete",
|
||||||
|
"user_tasteprofile_genre": "https://storeapi.kobo.com/v2/user/tasteprofile/genre",
|
||||||
"user_wishlist": "https://storeapi.kobo.com/v1/user/wishlist",
|
"user_wishlist": "https://storeapi.kobo.com/v1/user/wishlist",
|
||||||
"userguide_host": "https://ereaderfiles.kobo.com",
|
"userguide_host": "https://ereaderfiles.kobo.com",
|
||||||
"wishlist_page": "https://www.kobo.com/{region}/{language}/account/wishlist"
|
"wishlist_page": "https://www.kobo.com/{region}/{language}/account/wishlist"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ inline fun <R> Path.epub(block: (EpubPackage) -> R): R =
|
||||||
*/
|
*/
|
||||||
fun ZipFile.getPackagePath(): String =
|
fun ZipFile.getPackagePath(): String =
|
||||||
getEntryInputStream("META-INF/container.xml")
|
getEntryInputStream("META-INF/container.xml")
|
||||||
?.use { Jsoup.parse(it, null, "") }
|
?.use { Jsoup.parse(it, null, "", Parser.xmlParser()) }
|
||||||
?.getElementsByTag("rootfile")
|
?.getElementsByTag("rootfile")
|
||||||
?.first()
|
?.first()
|
||||||
?.attr("full-path") ?: throw MediaUnsupportedException("META-INF/container.xml does not contain rootfile tag")
|
?.attr("full-path") ?: throw MediaUnsupportedException("META-INF/container.xml does not contain rootfile tag")
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,14 @@ class EpubExtractor(
|
||||||
manifest.values.firstOrNull { it.properties.contains("cover-image") }
|
manifest.values.firstOrNull { it.properties.contains("cover-image") }
|
||||||
?: // EPUB 2 - get cover from meta element with name="cover"
|
?: // EPUB 2 - get cover from meta element with name="cover"
|
||||||
opfDoc
|
opfDoc
|
||||||
.selectFirst("metadata > meta[name=cover]")
|
.selectFirst("*|metadata > *|meta[name=cover]")
|
||||||
?.attr("content")
|
?.attr("content")
|
||||||
?.ifBlank { null }
|
?.ifBlank { null }
|
||||||
?.let { manifest[it] }
|
?.let { manifest[it] }
|
||||||
?: // try id="cover-image"
|
?: // try id="cover-image"
|
||||||
manifest.values.firstOrNull { it.id == "cover-image" }
|
manifest.values.firstOrNull { it.id == "cover-image" }
|
||||||
if (coverManifestItem != null) {
|
if (coverManifestItem != null) {
|
||||||
val href = coverManifestItem.href
|
val href = URLDecoder.decode(coverManifestItem.href, Charsets.UTF_8)
|
||||||
val mediaType = coverManifestItem.mediaType
|
val mediaType = coverManifestItem.mediaType
|
||||||
val coverPath = normalizeHref(opfDir, href)
|
val coverPath = normalizeHref(opfDir, href)
|
||||||
zip.getEntryBytes(coverPath)?.let { coverBytes ->
|
zip.getEntryBytes(coverPath)?.let { coverBytes ->
|
||||||
|
|
@ -84,7 +84,7 @@ class EpubExtractor(
|
||||||
fun getResources(epub: EpubPackage): List<MediaFile> {
|
fun getResources(epub: EpubPackage): List<MediaFile> {
|
||||||
val spine =
|
val spine =
|
||||||
epub.opfDoc
|
epub.opfDoc
|
||||||
.select("spine > itemref")
|
.select("*|spine > *|itemref")
|
||||||
.map { it.attr("idref") }
|
.map { it.attr("idref") }
|
||||||
.mapNotNull { epub.manifest[it] }
|
.mapNotNull { epub.manifest[it] }
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ class EpubExtractor(
|
||||||
run {
|
run {
|
||||||
val spine =
|
val spine =
|
||||||
epub.opfDoc
|
epub.opfDoc
|
||||||
.select("spine > itemref")
|
.select("*|spine > *|itemref")
|
||||||
.map { it.attr("idref") }
|
.map { it.attr("idref") }
|
||||||
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ class EpubExtractor(
|
||||||
|
|
||||||
val pagesWithImages =
|
val pagesWithImages =
|
||||||
epub.opfDoc
|
epub.opfDoc
|
||||||
.select("spine > itemref")
|
.select("*|spine > *|itemref")
|
||||||
.map { it.attr("idref") }
|
.map { it.attr("idref") }
|
||||||
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
||||||
.map { pagePath ->
|
.map { pagePath ->
|
||||||
|
|
@ -219,7 +219,7 @@ class EpubExtractor(
|
||||||
fun computePageCount(epub: EpubPackage): Int {
|
fun computePageCount(epub: EpubPackage): Int {
|
||||||
val spine =
|
val spine =
|
||||||
epub.opfDoc
|
epub.opfDoc
|
||||||
.select("spine > itemref")
|
.select("*|spine > *|itemref")
|
||||||
.map { it.attr("idref") }
|
.map { it.attr("idref") }
|
||||||
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
|
||||||
|
|
||||||
|
|
@ -230,8 +230,8 @@ class EpubExtractor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFixedLayout(epub: EpubPackage) =
|
fun isFixedLayout(epub: EpubPackage) =
|
||||||
epub.opfDoc.selectFirst("metadata > *|meta[property=rendition:layout]")?.text() == "pre-paginated" ||
|
epub.opfDoc.selectFirst("*|metadata > *|meta[property=rendition:layout]")?.text() == "pre-paginated" ||
|
||||||
epub.opfDoc.selectFirst("metadata > *|meta[name=fixed-layout]")?.attr("content") == "true"
|
epub.opfDoc.selectFirst("*|metadata > *|meta[name=fixed-layout]")?.attr("content") == "true"
|
||||||
|
|
||||||
fun computePositions(
|
fun computePositions(
|
||||||
epub: EpubPackage,
|
epub: EpubPackage,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.EpubTocEntry
|
||||||
import org.gotson.komga.infrastructure.util.getEntryBytes
|
import org.gotson.komga.infrastructure.util.getEntryBytes
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.parser.Parser
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
|
|
@ -23,7 +24,7 @@ fun processNcx(
|
||||||
navType: Epub2Nav,
|
navType: Epub2Nav,
|
||||||
): List<EpubTocEntry> =
|
): List<EpubTocEntry> =
|
||||||
Jsoup
|
Jsoup
|
||||||
.parse(document.content)
|
.parse(document.content, "", Parser.xmlParser())
|
||||||
.select("${navType.level1} > ${navType.level2}")
|
.select("${navType.level1} > ${navType.level2}")
|
||||||
.toList()
|
.toList()
|
||||||
.mapNotNull { ncxElementToTocEntry(navType, it, document.path.parent) }
|
.mapNotNull { ncxElementToTocEntry(navType, it, document.path.parent) }
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import java.nio.file.Paths
|
||||||
import kotlin.io.path.invariantSeparatorsPathString
|
import kotlin.io.path.invariantSeparatorsPathString
|
||||||
|
|
||||||
fun Document.getManifest() =
|
fun Document.getManifest() =
|
||||||
select("manifest > item").associate {
|
select("*|manifest > *|item").associate {
|
||||||
it.attr("id") to
|
it.attr("id") to
|
||||||
ManifestItem(
|
ManifestItem(
|
||||||
it.attr("id"),
|
it.attr("id"),
|
||||||
|
|
@ -36,8 +36,8 @@ fun processOpfGuide(
|
||||||
opf: Document,
|
opf: Document,
|
||||||
opfDir: Path?,
|
opfDir: Path?,
|
||||||
): List<EpubTocEntry> {
|
): List<EpubTocEntry> {
|
||||||
val guide = opf.selectFirst("guide") ?: return emptyList()
|
val guide = opf.selectFirst("*|guide") ?: return emptyList()
|
||||||
return guide.select("reference").map { ref ->
|
return guide.select("*|reference").map { ref ->
|
||||||
EpubTocEntry(
|
EpubTocEntry(
|
||||||
ref.attr("title"),
|
ref.attr("title"),
|
||||||
ref.attr("href").ifBlank { null }?.let { normalizeHref(opfDir, URLDecoder.decode(it, Charsets.UTF_8)) },
|
ref.attr("href").ifBlank { null }?.let { normalizeHref(opfDir, URLDecoder.decode(it, Charsets.UTF_8)) },
|
||||||
|
|
|
||||||
|
|
@ -51,22 +51,22 @@ class EpubMetadataProvider(
|
||||||
getPackageFileContent(book.book.path)?.let { packageFile ->
|
getPackageFileContent(book.book.path)?.let { packageFile ->
|
||||||
val opf = Jsoup.parse(packageFile, "", Parser.xmlParser())
|
val opf = Jsoup.parse(packageFile, "", Parser.xmlParser())
|
||||||
|
|
||||||
val title = opf.selectFirst("metadata > dc|title")?.text()?.ifBlank { null }
|
val title = opf.selectFirst("*|metadata > *|title")?.text()?.ifBlank { null }
|
||||||
val description =
|
val description =
|
||||||
opf
|
opf
|
||||||
.selectFirst("metadata > dc|description")
|
.selectFirst("*|metadata > *|description")
|
||||||
?.text()
|
?.text()
|
||||||
?.let { Jsoup.clean(it, Safelist.none()) }
|
?.let { Jsoup.clean(it, Safelist.none()) }
|
||||||
?.ifBlank { null }
|
?.ifBlank { null }
|
||||||
val date = opf.selectFirst("metadata > dc|date")?.text()?.let { parseDate(it) }
|
val date = opf.selectFirst("*|metadata > *|date")?.text()?.let { parseDate(it) }
|
||||||
|
|
||||||
val authorRoles =
|
val authorRoles =
|
||||||
opf
|
opf
|
||||||
.select("metadata > *|meta[property=role][scheme=marc:relators]")
|
.select("*|metadata > *|meta[property=role][scheme=marc:relators]")
|
||||||
.associate { it.attr("refines").removePrefix("#") to it.text() }
|
.associate { it.attr("refines").removePrefix("#") to it.text() }
|
||||||
val authors =
|
val authors =
|
||||||
opf
|
opf
|
||||||
.select("metadata > dc|creator")
|
.select("*|metadata > *|creator")
|
||||||
.mapNotNull { el ->
|
.mapNotNull { el ->
|
||||||
val name = el.text().trim()
|
val name = el.text().trim()
|
||||||
if (name.isBlank()) {
|
if (name.isBlank()) {
|
||||||
|
|
@ -81,16 +81,16 @@ class EpubMetadataProvider(
|
||||||
|
|
||||||
val isbn =
|
val isbn =
|
||||||
opf
|
opf
|
||||||
.select("metadata > dc|identifier")
|
.select("*|metadata > *|identifier")
|
||||||
.map { it.text().lowercase().removePrefix("isbn:") }
|
.map { it.text().lowercase().removePrefix("isbn:") }
|
||||||
.firstNotNullOfOrNull { isbnValidator.validate(it) }
|
.firstNotNullOfOrNull { isbnValidator.validate(it) }
|
||||||
|
|
||||||
val seriesIndex =
|
val seriesIndex =
|
||||||
opf
|
opf
|
||||||
.selectFirst("metadata > *|meta[property=belongs-to-collection]")
|
.selectFirst("*|metadata > *|meta[property=belongs-to-collection]")
|
||||||
?.attr("id")
|
?.attr("id")
|
||||||
?.let { id ->
|
?.let { id ->
|
||||||
opf.selectFirst("metadata > *|meta[refines=#$id][property=group-position]")
|
opf.selectFirst("*|metadata > *|meta[refines=#$id][property=group-position]")
|
||||||
}?.text()
|
}?.text()
|
||||||
|
|
||||||
return BookMetadataPatch(
|
return BookMetadataPatch(
|
||||||
|
|
@ -116,18 +116,18 @@ class EpubMetadataProvider(
|
||||||
getPackageFileContent(book.book.path)?.let { packageFile ->
|
getPackageFileContent(book.book.path)?.let { packageFile ->
|
||||||
val opf = Jsoup.parse(packageFile, "", Parser.xmlParser())
|
val opf = Jsoup.parse(packageFile, "", Parser.xmlParser())
|
||||||
|
|
||||||
val series = opf.selectFirst("metadata > *|meta[property=belongs-to-collection]")?.text()?.ifBlank { null }
|
val series = opf.selectFirst("*|metadata > *|meta[property=belongs-to-collection]")?.text()?.ifBlank { null }
|
||||||
val publisher = opf.selectFirst("metadata > dc|publisher")?.text()?.ifBlank { null }
|
val publisher = opf.selectFirst("*|metadata > *|publisher")?.text()?.ifBlank { null }
|
||||||
val language = opf.selectFirst("metadata > dc|language")?.text()?.ifBlank { null }
|
val language = opf.selectFirst("*|metadata > *|language")?.text()?.ifBlank { null }
|
||||||
val genres =
|
val genres =
|
||||||
opf
|
opf
|
||||||
.select("metadata > dc|subject")
|
.select("*|metadata > *|subject")
|
||||||
.mapNotNull { it.text().trim().ifBlank { null } }
|
.mapNotNull { it.text().trim().ifBlank { null } }
|
||||||
.toSet()
|
.toSet()
|
||||||
.ifEmpty { null }
|
.ifEmpty { null }
|
||||||
|
|
||||||
val direction =
|
val direction =
|
||||||
opf.getElementsByTag("spine").first()?.attr("page-progression-direction")?.let {
|
opf.selectFirst("*|spine")?.attr("page-progression-direction")?.let {
|
||||||
when (it) {
|
when (it) {
|
||||||
"rtl" -> SeriesMetadata.ReadingDirection.RIGHT_TO_LEFT
|
"rtl" -> SeriesMetadata.ReadingDirection.RIGHT_TO_LEFT
|
||||||
"ltr" -> SeriesMetadata.ReadingDirection.LEFT_TO_RIGHT
|
"ltr" -> SeriesMetadata.ReadingDirection.LEFT_TO_RIGHT
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class LocalArtworkProvider(
|
||||||
private val imageAnalyzer: ImageAnalyzer,
|
private val imageAnalyzer: ImageAnalyzer,
|
||||||
) : SidecarSeriesConsumer,
|
) : SidecarSeriesConsumer,
|
||||||
SidecarBookConsumer {
|
SidecarBookConsumer {
|
||||||
val supportedExtensions = listOf("png", "jpeg", "jpg", "tbn", "webp")
|
val supportedExtensions = listOf("png", "jpeg", "jpg", "tbn", "webp", "gif")
|
||||||
val supportedSeriesFiles = listOf("cover", "default", "folder", "poster", "series")
|
val supportedSeriesFiles = listOf("cover", "default", "folder", "poster", "series")
|
||||||
|
|
||||||
fun getBookThumbnails(book: Book): List<ThumbnailBook> {
|
fun getBookThumbnails(book: Book): List<ThumbnailBook> {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.security
|
||||||
import jakarta.servlet.Filter
|
import jakarta.servlet.Filter
|
||||||
import org.gotson.komga.domain.model.UserRoles
|
import org.gotson.komga.domain.model.UserRoles
|
||||||
import org.gotson.komga.infrastructure.configuration.KomgaSettingsProvider
|
import org.gotson.komga.infrastructure.configuration.KomgaSettingsProvider
|
||||||
|
import org.gotson.komga.infrastructure.hash.Hasher
|
||||||
import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationFilter
|
import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationFilter
|
||||||
import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationProvider
|
import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationProvider
|
||||||
import org.gotson.komga.infrastructure.security.apikey.HeaderApiKeyAuthenticationConverter
|
import org.gotson.komga.infrastructure.security.apikey.HeaderApiKeyAuthenticationConverter
|
||||||
|
|
@ -34,6 +35,7 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
|
||||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
||||||
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices
|
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
@ -51,6 +53,7 @@ class SecurityConfiguration(
|
||||||
private val opdsAuthenticationEntryPoint: OpdsAuthenticationEntryPoint,
|
private val opdsAuthenticationEntryPoint: OpdsAuthenticationEntryPoint,
|
||||||
private val authenticationEventPublisher: AuthenticationEventPublisher,
|
private val authenticationEventPublisher: AuthenticationEventPublisher,
|
||||||
private val tokenEncoder: TokenEncoder,
|
private val tokenEncoder: TokenEncoder,
|
||||||
|
private val hasher: Hasher,
|
||||||
clientRegistrationRepository: InMemoryClientRegistrationRepository?,
|
clientRegistrationRepository: InMemoryClientRegistrationRepository?,
|
||||||
) {
|
) {
|
||||||
private val oauth2Enabled = clientRegistrationRepository != null
|
private val oauth2Enabled = clientRegistrationRepository != null
|
||||||
|
|
@ -158,7 +161,7 @@ class SecurityConfiguration(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
http.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter::class.java)
|
http.addFilterAfter(restAuthenticationFilter(), BasicAuthenticationFilter::class.java)
|
||||||
|
|
||||||
return http.build()
|
return http.build()
|
||||||
}
|
}
|
||||||
|
|
@ -239,19 +242,19 @@ class SecurityConfiguration(
|
||||||
fun koboAuthenticationFilter(): Filter =
|
fun koboAuthenticationFilter(): Filter =
|
||||||
ApiKeyAuthenticationFilter(
|
ApiKeyAuthenticationFilter(
|
||||||
apiKeyAuthenticationProvider(),
|
apiKeyAuthenticationProvider(),
|
||||||
UriRegexApiKeyAuthenticationConverter(Regex("""/kobo/([\w-]+)"""), tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
UriRegexApiKeyAuthenticationConverter(Regex("""/kobo/([\w-]+)"""), hasher, tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun kosyncAuthenticationFilter(): Filter =
|
fun kosyncAuthenticationFilter(): Filter =
|
||||||
ApiKeyAuthenticationFilter(
|
ApiKeyAuthenticationFilter(
|
||||||
apiKeyAuthenticationProvider(),
|
apiKeyAuthenticationProvider(),
|
||||||
HeaderApiKeyAuthenticationConverter("X-Auth-User", tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
HeaderApiKeyAuthenticationConverter("X-Auth-User", hasher, tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun restAuthenticationFilter(): Filter =
|
fun restAuthenticationFilter(): Filter =
|
||||||
ApiKeyAuthenticationFilter(
|
ApiKeyAuthenticationFilter(
|
||||||
apiKeyAuthenticationProvider(),
|
apiKeyAuthenticationProvider(),
|
||||||
HeaderApiKeyAuthenticationConverter("X-API-Key", tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
HeaderApiKeyAuthenticationConverter("X-API-Key", hasher, tokenEncoder, userAgentWebAuthenticationDetailsSource),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun apiKeyAuthenticationProvider(): AuthenticationManager =
|
fun apiKeyAuthenticationProvider(): AuthenticationManager =
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ class ApiKeyAuthenticationFilter(
|
||||||
} catch (ex: AuthenticationException) {
|
} catch (ex: AuthenticationException) {
|
||||||
unsuccessfulAuthentication(request, response, ex)
|
unsuccessfulAuthentication(request, response, ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsuccessfulAuthentication(
|
private fun unsuccessfulAuthentication(
|
||||||
|
|
@ -78,7 +80,6 @@ class ApiKeyAuthenticationFilter(
|
||||||
}
|
}
|
||||||
securityContextHolderStrategy.context = context
|
securityContextHolderStrategy.context = context
|
||||||
securityContextRepository.saveContext(context, request, response)
|
securityContextRepository.saveContext(context, request, response)
|
||||||
filterChain.doFilter(request, response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun authenticationIsRequired(username: String): Boolean {
|
private fun authenticationIsRequired(username: String): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.gotson.komga.infrastructure.security.apikey
|
package org.gotson.komga.infrastructure.security.apikey
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import org.gotson.komga.infrastructure.hash.Hasher
|
||||||
import org.gotson.komga.infrastructure.security.TokenEncoder
|
import org.gotson.komga.infrastructure.security.TokenEncoder
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource
|
import org.springframework.security.authentication.AuthenticationDetailsSource
|
||||||
import org.springframework.security.core.Authentication
|
import org.springframework.security.core.Authentication
|
||||||
|
|
@ -11,11 +12,13 @@ import org.springframework.security.web.authentication.AuthenticationConverter
|
||||||
* and convert it to an [ApiKeyAuthenticationToken]
|
* and convert it to an [ApiKeyAuthenticationToken]
|
||||||
*
|
*
|
||||||
* @property headerName the header name from which to retrieve the API key
|
* @property headerName the header name from which to retrieve the API key
|
||||||
|
* @property hasher the hasher to use to encode the API key as username in the [Authentication] object
|
||||||
* @property tokenEncoder the encoder to use to encode the API key in the [Authentication] object
|
* @property tokenEncoder the encoder to use to encode the API key in the [Authentication] object
|
||||||
* @property authenticationDetailsSource the [AuthenticationDetailsSource] to enrich the [Authentication] details
|
* @property authenticationDetailsSource the [AuthenticationDetailsSource] to enrich the [Authentication] details
|
||||||
*/
|
*/
|
||||||
class HeaderApiKeyAuthenticationConverter(
|
class HeaderApiKeyAuthenticationConverter(
|
||||||
private val headerName: String,
|
private val headerName: String,
|
||||||
|
private val hasher: Hasher,
|
||||||
private val tokenEncoder: TokenEncoder,
|
private val tokenEncoder: TokenEncoder,
|
||||||
private val authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>,
|
private val authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>,
|
||||||
) : AuthenticationConverter {
|
) : AuthenticationConverter {
|
||||||
|
|
@ -23,7 +26,8 @@ class HeaderApiKeyAuthenticationConverter(
|
||||||
request
|
request
|
||||||
.getHeader(headerName)
|
.getHeader(headerName)
|
||||||
?.let {
|
?.let {
|
||||||
val (maskedToken, hashedToken) = it.take(6) + "*".repeat(6) to tokenEncoder.encode(it)
|
val maskedToken = hasher.computeHash(it)
|
||||||
|
val hashedToken = tokenEncoder.encode(it)
|
||||||
ApiKeyAuthenticationToken
|
ApiKeyAuthenticationToken
|
||||||
.unauthenticated(maskedToken, hashedToken)
|
.unauthenticated(maskedToken, hashedToken)
|
||||||
.apply { details = authenticationDetailsSource.buildDetails(request) }
|
.apply { details = authenticationDetailsSource.buildDetails(request) }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.gotson.komga.infrastructure.security.apikey
|
package org.gotson.komga.infrastructure.security.apikey
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import org.gotson.komga.infrastructure.hash.Hasher
|
||||||
import org.gotson.komga.infrastructure.security.TokenEncoder
|
import org.gotson.komga.infrastructure.security.TokenEncoder
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource
|
import org.springframework.security.authentication.AuthenticationDetailsSource
|
||||||
import org.springframework.security.core.Authentication
|
import org.springframework.security.core.Authentication
|
||||||
|
|
@ -11,11 +12,13 @@ import org.springframework.security.web.authentication.AuthenticationConverter
|
||||||
* request URI, and convert it to an [ApiKeyAuthenticationToken]
|
* request URI, and convert it to an [ApiKeyAuthenticationToken]
|
||||||
*
|
*
|
||||||
* @property tokenRegex the regex used to extract the API key
|
* @property tokenRegex the regex used to extract the API key
|
||||||
* @property tokenEncoder the encoder to use to encode the API key in the [Authentication] object
|
* @property hasher the hasher to use to encode the API key as username in the [Authentication] object
|
||||||
|
* @property tokenEncoder the encoder to use to encode the API key as credentials in the [Authentication] object
|
||||||
* @property authenticationDetailsSource the [AuthenticationDetailsSource] to enrich the [Authentication] details
|
* @property authenticationDetailsSource the [AuthenticationDetailsSource] to enrich the [Authentication] details
|
||||||
*/
|
*/
|
||||||
class UriRegexApiKeyAuthenticationConverter(
|
class UriRegexApiKeyAuthenticationConverter(
|
||||||
private val tokenRegex: Regex,
|
private val tokenRegex: Regex,
|
||||||
|
private val hasher: Hasher,
|
||||||
private val tokenEncoder: TokenEncoder,
|
private val tokenEncoder: TokenEncoder,
|
||||||
private val authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>,
|
private val authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>,
|
||||||
) : AuthenticationConverter {
|
) : AuthenticationConverter {
|
||||||
|
|
@ -24,7 +27,8 @@ class UriRegexApiKeyAuthenticationConverter(
|
||||||
?.let {
|
?.let {
|
||||||
tokenRegex.find(it)?.groupValues?.lastOrNull()
|
tokenRegex.find(it)?.groupValues?.lastOrNull()
|
||||||
}?.let {
|
}?.let {
|
||||||
val (maskedToken, hashedToken) = it.take(6) + "*".repeat(6) to tokenEncoder.encode(it)
|
val maskedToken = hasher.computeHash(it)
|
||||||
|
val hashedToken = tokenEncoder.encode(it)
|
||||||
ApiKeyAuthenticationToken
|
ApiKeyAuthenticationToken
|
||||||
.unauthenticated(maskedToken, hashedToken)
|
.unauthenticated(maskedToken, hashedToken)
|
||||||
.apply { details = authenticationDetailsSource.buildDetails(request) }
|
.apply { details = authenticationDetailsSource.buildDetails(request) }
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ fun ResponseEntity.BodyBuilder.setCachePrivate() = this.cacheControl(cachePrivat
|
||||||
val cachePrivate =
|
val cachePrivate =
|
||||||
CacheControl
|
CacheControl
|
||||||
.maxAge(0, TimeUnit.SECONDS)
|
.maxAge(0, TimeUnit.SECONDS)
|
||||||
.noTransform()
|
|
||||||
.cachePrivate()
|
.cachePrivate()
|
||||||
.mustRevalidate()
|
.mustRevalidate()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,7 @@ class KoboController(
|
||||||
try {
|
try {
|
||||||
koboProxy.proxyCurrentRequest().body?.get("Resources")
|
koboProxy.proxyCurrentRequest().body?.get("Resources")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
if (e is ResponseStatusException && e.statusCode == HttpStatus.UNAUTHORIZED) throw e
|
||||||
logger.warn { "Failed to get response from Kobo /v1/initialization, fallback to noproxy" }
|
logger.warn { "Failed to get response from Kobo /v1/initialization, fallback to noproxy" }
|
||||||
null
|
null
|
||||||
} ?: koboProxy.nativeKoboResources
|
} ?: koboProxy.nativeKoboResources
|
||||||
|
|
@ -233,7 +234,7 @@ class KoboController(
|
||||||
): Any {
|
): Any {
|
||||||
try {
|
try {
|
||||||
return koboProxy.proxyCurrentRequest(body)
|
return koboProxy.proxyCurrentRequest(body)
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
logger.warn { "Failed to get response from Kobo /v1/auth/device, fallback to noproxy" }
|
logger.warn { "Failed to get response from Kobo /v1/auth/device, fallback to noproxy" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -395,7 +396,7 @@ class KoboController(
|
||||||
addAll(
|
addAll(
|
||||||
// changed books are also passed as changed reading state because Kobo does not process ChangedEntitlement even if it contains a ReadingState
|
// changed books are also passed as changed reading state because Kobo does not process ChangedEntitlement even if it contains a ReadingState
|
||||||
(booksChanged.content + changedReadingState.content).mapNotNull { book ->
|
(booksChanged.content + changedReadingState.content).mapNotNull { book ->
|
||||||
readProgress[book.bookId]?.let { it ->
|
readProgress[book.bookId]?.let {
|
||||||
ChangedReadingStateDto(
|
ChangedReadingStateDto(
|
||||||
WrappedReadingStateDto(
|
WrappedReadingStateDto(
|
||||||
it.toDto(),
|
it.toDto(),
|
||||||
|
|
@ -570,7 +571,10 @@ class KoboController(
|
||||||
locator =
|
locator =
|
||||||
if (koboUpdate.statusInfo.status == StatusDto.FINISHED) {
|
if (koboUpdate.statusInfo.status == StatusDto.FINISHED) {
|
||||||
// If the book is finished, Kobo sends the first resource instead of the last, so we can't trust what Kobo sent
|
// If the book is finished, Kobo sends the first resource instead of the last, so we can't trust what Kobo sent
|
||||||
val epubExtension = mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub ?: throw IllegalArgumentException("Epub extension not found")
|
val epubExtension =
|
||||||
|
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
||||||
|
?: throw IllegalArgumentException("Epub extension not found")
|
||||||
|
.also { logger.error { "Epub extension not found for book ${book.id}. Book should be re-analyzed." } }
|
||||||
epubExtension.positions.last()
|
epubExtension.positions.last()
|
||||||
} else {
|
} else {
|
||||||
R2Locator(
|
R2Locator(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gotson.komga.interfaces.api.kosync
|
package org.gotson.komga.interfaces.api.kosync
|
||||||
|
|
||||||
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import org.gotson.komga.domain.model.MediaExtensionEpub
|
import org.gotson.komga.domain.model.MediaExtensionEpub
|
||||||
import org.gotson.komga.domain.model.MediaProfile
|
import org.gotson.komga.domain.model.MediaProfile
|
||||||
import org.gotson.komga.domain.model.R2Device
|
import org.gotson.komga.domain.model.R2Device
|
||||||
|
|
@ -25,6 +26,8 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
import org.springframework.web.server.ResponseStatusException
|
import org.springframework.web.server.ResponseStatusException
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/koreader", produces = ["application/vnd.koreader.v1+json"])
|
@RequestMapping("/koreader", produces = ["application/vnd.koreader.v1+json"])
|
||||||
class KoreaderSyncController(
|
class KoreaderSyncController(
|
||||||
|
|
@ -48,8 +51,14 @@ class KoreaderSyncController(
|
||||||
@PathVariable bookHash: String,
|
@PathVariable bookHash: String,
|
||||||
): DocumentProgressDto {
|
): DocumentProgressDto {
|
||||||
val books = bookRepository.findAllByHashKoreader(bookHash)
|
val books = bookRepository.findAllByHashKoreader(bookHash)
|
||||||
if (books.isEmpty()) throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found")
|
if (books.isEmpty()) {
|
||||||
if (books.size > 1) throw ResponseStatusException(HttpStatus.CONFLICT, "More than 1 book found with the same hash")
|
logger.debug { "No book found with KOReader hash: $bookHash" }
|
||||||
|
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found")
|
||||||
|
}
|
||||||
|
if (books.size > 1) {
|
||||||
|
logger.debug { "No unique book found with KOReader hash: $bookHash. Found ${books.size} books with the same hash." }
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "More than 1 book found with the same hash")
|
||||||
|
}
|
||||||
|
|
||||||
val book = books.first()
|
val book = books.first()
|
||||||
val media = mediaRepository.findById(book.id)
|
val media = mediaRepository.findById(book.id)
|
||||||
|
|
@ -69,7 +78,10 @@ class KoreaderSyncController(
|
||||||
when (media.profile) {
|
when (media.profile) {
|
||||||
MediaProfile.DIVINA, MediaProfile.PDF -> readProgress.page.toString()
|
MediaProfile.DIVINA, MediaProfile.PDF -> readProgress.page.toString()
|
||||||
MediaProfile.EPUB -> {
|
MediaProfile.EPUB -> {
|
||||||
val extension = mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Epub extension not found")
|
val extension =
|
||||||
|
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
||||||
|
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Epub extension not found")
|
||||||
|
.also { logger.error { "Epub extension not found for book ${book.id}. Book should be re-analyzed." } }
|
||||||
|
|
||||||
// convert the href to its index for KOReader
|
// convert the href to its index for KOReader
|
||||||
val resourceIndex =
|
val resourceIndex =
|
||||||
|
|
@ -81,6 +93,7 @@ class KoreaderSyncController(
|
||||||
// return a progress string that points to the beginning of the resource
|
// return a progress string that points to the beginning of the resource
|
||||||
"/body/DocFragment[${resourceIndex + 1}].0"
|
"/body/DocFragment[${resourceIndex + 1}].0"
|
||||||
}
|
}
|
||||||
|
|
||||||
null -> throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book has no media profile")
|
null -> throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book has no media profile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,8 +112,14 @@ class KoreaderSyncController(
|
||||||
@RequestBody koreaderProgress: DocumentProgressDto,
|
@RequestBody koreaderProgress: DocumentProgressDto,
|
||||||
) {
|
) {
|
||||||
val books = bookRepository.findAllByHashKoreader(koreaderProgress.document)
|
val books = bookRepository.findAllByHashKoreader(koreaderProgress.document)
|
||||||
if (books.isEmpty()) throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found")
|
if (books.isEmpty()) {
|
||||||
if (books.size > 1) throw ResponseStatusException(HttpStatus.CONFLICT, "More than 1 book found with the same hash")
|
logger.debug { "No book found with KOReader hash: ${koreaderProgress.document}" }
|
||||||
|
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found")
|
||||||
|
}
|
||||||
|
if (books.size > 1) {
|
||||||
|
logger.debug { "No unique book found with KOReader hash: ${koreaderProgress.document}. Found ${books.size} books with the same hash." }
|
||||||
|
throw ResponseStatusException(HttpStatus.CONFLICT, "More than 1 book found with the same hash")
|
||||||
|
}
|
||||||
|
|
||||||
val book = books.first()
|
val book = books.first()
|
||||||
val media = mediaRepository.findById(book.id)
|
val media = mediaRepository.findById(book.id)
|
||||||
|
|
@ -139,8 +158,12 @@ class KoreaderSyncController(
|
||||||
?.value
|
?.value
|
||||||
?.toIntOrNull()
|
?.toIntOrNull()
|
||||||
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not get Epub resource index from progress: ${koreaderProgress.progress}")
|
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not get Epub resource index from progress: ${koreaderProgress.progress}")
|
||||||
|
.also { logger.error { "Could not get Epub resource index from progress: ${koreaderProgress.progress}" } }
|
||||||
|
|
||||||
val extension = mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Epub extension not found")
|
val extension =
|
||||||
|
mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub
|
||||||
|
?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Epub extension not found")
|
||||||
|
.also { logger.error { "Epub extension not found for book ${book.id}. Book should be re-analyzed." } }
|
||||||
|
|
||||||
// get the href from the index provided by KOReader
|
// get the href from the index provided by KOReader
|
||||||
val href =
|
val href =
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ class ReadListController(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "Match ComicRack list", tags = [OpenApiConfiguration.TagNames.COMICRACK])
|
@Operation(summary = "Match ComicRack list", tags = [OpenApiConfiguration.TagNames.COMICRACK])
|
||||||
@PostMapping("match/comicrack")
|
@PostMapping("match/comicrack", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
fun matchComicRackList(
|
fun matchComicRackList(
|
||||||
@RequestParam("file") file: MultipartFile,
|
@RequestParam("file") file: MultipartFile,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.rest.dto
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
data class HistoricalEventDto(
|
data class HistoricalEventDto(
|
||||||
|
val id: String,
|
||||||
val type: String,
|
val type: String,
|
||||||
val timestamp: LocalDateTime,
|
val timestamp: LocalDateTime,
|
||||||
val bookId: String?,
|
val bookId: String?,
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ class SettingsUpdateDto {
|
||||||
isSet[prop.name] = true
|
isSet[prop.name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Will be removed in a future version")
|
||||||
var kepubifyPath: String?
|
var kepubifyPath: String?
|
||||||
by Delegates.observable(null) { prop, _, _ ->
|
by Delegates.observable(null) { prop, _, _ ->
|
||||||
isSet[prop.name] = true
|
isSet[prop.name] = true
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,9 @@ spring:
|
||||||
jackson:
|
jackson:
|
||||||
deserialization:
|
deserialization:
|
||||||
FAIL_ON_NULL_FOR_PRIMITIVES: true
|
FAIL_ON_NULL_FOR_PRIMITIVES: true
|
||||||
|
mapper:
|
||||||
|
accept-case-insensitive-properties: true
|
||||||
|
accept-case-insensitive-values: true
|
||||||
config:
|
config:
|
||||||
import:
|
import:
|
||||||
- "optional:file:\${komga.config-dir}/application.yml"
|
- "optional:file:\${komga.config-dir}/application.yml"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import javax.sql.DataSource
|
||||||
|
|
||||||
class DataSourcesConfigurationTest {
|
class DataSourcesConfigurationTest {
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@ActiveProfiles("test", "waltest")
|
|
||||||
@Nested
|
@Nested
|
||||||
inner class WalMode(
|
inner class WalMode(
|
||||||
@Autowired private val dataSourceRW: DataSource,
|
@Autowired private val dataSourceRW: DataSource,
|
||||||
|
|
@ -27,6 +26,7 @@ class DataSourcesConfigurationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
|
@ActiveProfiles("test", "memorydb")
|
||||||
@Nested
|
@Nested
|
||||||
inner class MemoryMode(
|
inner class MemoryMode(
|
||||||
@Autowired private val dataSourceRW: DataSource,
|
@Autowired private val dataSourceRW: DataSource,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import org.gotson.komga.infrastructure.mediacontainer.epub.getPackageFileContent
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.Nested
|
import org.junit.jupiter.api.Nested
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource
|
||||||
import org.springframework.core.io.ClassPathResource
|
import org.springframework.core.io.ClassPathResource
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
|
@ -37,9 +39,15 @@ class EpubMetadataProviderTest {
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
inner class Book {
|
inner class Book {
|
||||||
@Test
|
@ParameterizedTest
|
||||||
fun `given epub 3 opf when getting book metadata then metadata patch is valid`() {
|
@ValueSource(
|
||||||
val opf = ClassPathResource("epub/Panik im Paradies.opf")
|
strings = [
|
||||||
|
"epub/Panik im Paradies.opf",
|
||||||
|
"epub/Panik im Paradies - namespace.opf",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
fun `given epub 3 opf when getting book metadata then metadata patch is valid`(opfFile: String) {
|
||||||
|
val opf = ClassPathResource(opfFile)
|
||||||
mockkStatic(::getPackageFileContent)
|
mockkStatic(::getPackageFileContent)
|
||||||
every { getPackageFileContent(any()) } returns opf.file.readText()
|
every { getPackageFileContent(any()) } returns opf.file.readText()
|
||||||
|
|
||||||
|
|
@ -128,9 +136,15 @@ class EpubMetadataProviderTest {
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
inner class Series {
|
inner class Series {
|
||||||
@Test
|
@ParameterizedTest
|
||||||
fun `given epub 3 opf when getting series metadata then metadata patch is valid`() {
|
@ValueSource(
|
||||||
val opf = ClassPathResource("epub/Panik im Paradies.opf")
|
strings = [
|
||||||
|
"epub/Panik im Paradies.opf",
|
||||||
|
"epub/Panik im Paradies - namespace.opf",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
fun `given epub 3 opf when getting series metadata then metadata patch is valid`(opfFile: String) {
|
||||||
|
val opf = ClassPathResource(opfFile)
|
||||||
mockkStatic(::getPackageFileContent)
|
mockkStatic(::getPackageFileContent)
|
||||||
every { getPackageFileContent(any()) } returns opf.file.readText()
|
every { getPackageFileContent(any()) } returns opf.file.readText()
|
||||||
|
|
||||||
|
|
|
||||||
5
komga/src/test/resources/application-memorydb.yml
Normal file
5
komga/src/test/resources/application-memorydb.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
komga:
|
||||||
|
database:
|
||||||
|
file: "file:database?mode=memory"
|
||||||
|
tasks-db:
|
||||||
|
file: "file:tasks?mode=memory"
|
||||||
|
|
@ -2,9 +2,11 @@ application.version: TESTING
|
||||||
|
|
||||||
komga:
|
komga:
|
||||||
database:
|
database:
|
||||||
file: "file:database?mode=memory"
|
file: "\${java.io.tmpdir}/database\${random.uuid}.sqlite"
|
||||||
|
journal-mode: WAL
|
||||||
tasks-db:
|
tasks-db:
|
||||||
file: "file:tasks?mode=memory"
|
file: "\${java.io.tmpdir}/tasks\${random.uuid}.sqlite"
|
||||||
|
journal-mode: WAL
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
flyway:
|
flyway:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
komga:
|
|
||||||
database:
|
|
||||||
file: "\${java.io.tmpdir}/database.sqlite"
|
|
||||||
journal-mode: WAL
|
|
||||||
tasks-db:
|
|
||||||
file: "\${java.io.tmpdir}/tasks.sqlite"
|
|
||||||
journal-mode: WAL
|
|
||||||
128
komga/src/test/resources/epub/Panik im Paradies - namespace.opf
Normal file
128
komga/src/test/resources/epub/Panik im Paradies - namespace.opf
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
<myopf:package xmlns:myopf="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="uuid_id" prefix="calibre: https://calibre-ebook.com">
|
||||||
|
<myopf:metadata xmlns:mydc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:dcterms="http://purl.org/dc/terms/"
|
||||||
|
xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata">
|
||||||
|
<mydc:title id="id">Panik im Paradies</mydc:title>
|
||||||
|
<mydc:creator id="id-1">Ulf Blanck</mydc:creator>
|
||||||
|
<mydc:creator id="id-3">The Editor</mydc:creator>
|
||||||
|
<mydc:identifier>goodreads:222735</mydc:identifier>
|
||||||
|
<mydc:identifier>isbn:9783440077894</mydc:identifier>
|
||||||
|
<mydc:identifier>calibre:255</mydc:identifier>
|
||||||
|
<mydc:identifier>uuid:499def46-39dc-4e79-b474-d0ec12ea5dc5</mydc:identifier>
|
||||||
|
<mydc:identifier id="uuid_id">uuid:499def46-39dc-4e79-b474-d0ec12ea5dc5</mydc:identifier>
|
||||||
|
<mydc:language>de</mydc:language>
|
||||||
|
<mydc:date>1999-07-31T16:00:00+00:00</mydc:date>
|
||||||
|
<mydc:description><div>
|
||||||
|
<p>Bereits im ersten Band "Panik im Paradies" machen die drei berühmten Detektive ihrem Namen alle Ehre. Eigentlich haben sie ja gerade Ferien. Doch dann treffen sie auf diesen schrulligen Kapitän Larsson, der sich einen kleinen Privatzoo mit exotischen Tieren hält. Als plötzlich alle Tiere an rätselhaften Infektionen erkranken und die Besucher ausbleiben, werden Justus, Peter und Bob neugierig. Schon bald merken sie, daß da jemand ein düsteres Geheimnis hütet...</p></div></mydc:description>
|
||||||
|
<mydc:publisher>Kosmos</mydc:publisher>
|
||||||
|
<mydc:subject>Kinder- und Jugendbücher</mydc:subject>
|
||||||
|
<myopf:meta refines="#id" property="title-type">main</myopf:meta>
|
||||||
|
<myopf:meta refines="#id" property="file-as">Panik im Paradies</myopf:meta>
|
||||||
|
<myopf:meta name="cover" content="cover"/>
|
||||||
|
<myopf:meta property="calibre:timestamp" scheme="dcterms:W3CDTF">2020-08-09T08:40:58Z</myopf:meta>
|
||||||
|
<myopf:meta property="dcterms:modified" scheme="dcterms:W3CDTF">2021-06-19T08:20:33Z</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-1" property="role" scheme="marc:relators">aut</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-1" property="file-as">Blanck, Ulf</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-3" property="role" scheme="marc:relators">edt</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-3" property="file-as">Editor, The</myopf:meta>
|
||||||
|
<myopf:meta property="calibre:rating">6</myopf:meta>
|
||||||
|
<myopf:meta property="belongs-to-collection" id="id-2">Die drei ??? Kids</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-2" property="collection-type">series</myopf:meta>
|
||||||
|
<myopf:meta refines="#id-2" property="group-position">1.5</myopf:meta>
|
||||||
|
<myopf:meta property="calibre:author_link_map">{"Ulf Blanck": ""}</myopf:meta>
|
||||||
|
</myopf:metadata>
|
||||||
|
<myopf:manifest>
|
||||||
|
<myopf:item id="titlepage" href="titlepage.xhtml" media-type="application/xhtml+xml" properties="svg calibre:title-page"/>
|
||||||
|
<myopf:item id="TableOfContents_html" href="OPS/TableOfContents.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0001_html" href="OPS/section-0001.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0002_html" href="OPS/section-0002.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0003_html" href="OPS/section-0003.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0004_html" href="OPS/section-0004.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0005_html" href="OPS/section-0005.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0006_html" href="OPS/section-0006.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0007_html" href="OPS/section-0007.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0008_html" href="OPS/section-0008.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0009_html" href="OPS/section-0009.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0010_html" href="OPS/section-0010.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0011_html" href="OPS/section-0011.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0012_html" href="OPS/section-0012.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0013_html" href="OPS/section-0013.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0014_html" href="OPS/section-0014.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0015_html" href="OPS/section-0015.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0016_html" href="OPS/section-0016.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0017_html" href="OPS/section-0017.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0018_html" href="OPS/section-0018.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0019_html" href="OPS/section-0019.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0020_html" href="OPS/section-0020.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0021_html" href="OPS/section-0021.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0022_html" href="OPS/section-0022.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="section-0023_html" href="OPS/section-0023.html" media-type="application/xhtml+xml"/>
|
||||||
|
<myopf:item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
|
||||||
|
<myopf:item id="page_css" href="page_styles.css" media-type="text/css"/>
|
||||||
|
<myopf:item id="css" href="stylesheet.css" media-type="text/css"/>
|
||||||
|
<myopf:item id="cover" href="cover.jpeg" media-type="image/jpeg" properties="cover-image"/>
|
||||||
|
<myopf:item id="image0_jpg" href="OPS/image0.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image1_jpg" href="OPS/image1.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image10_jpg" href="OPS/image10.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image11_jpg" href="OPS/image11.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image12_jpg" href="OPS/image12.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image13_jpg" href="OPS/image13.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image14_jpg" href="OPS/image14.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image15_jpg" href="OPS/image15.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image16_jpg" href="OPS/image16.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image17_jpg" href="OPS/image17.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image18_jpg" href="OPS/image18.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image19_jpg" href="OPS/image19.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image2_jpg" href="OPS/image2.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image20_jpg" href="OPS/image20.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image21_jpg" href="OPS/image21.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image22_jpg" href="OPS/image22.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image23_jpg" href="OPS/image23.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image24_jpg" href="OPS/image24.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image25_jpg" href="OPS/image25.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image26_jpg" href="OPS/image26.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image27_jpg" href="OPS/image27.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image28_jpg" href="OPS/image28.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image29_jpg" href="OPS/image29.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image3_jpg" href="OPS/image3.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image30_jpg" href="OPS/image30.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image31_jpg" href="OPS/image31.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image32_jpg" href="OPS/image32.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image33_jpg" href="OPS/image33.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image34_jpg" href="OPS/image34.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image35_jpg" href="OPS/image35.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image4_jpg" href="OPS/image4.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image5_jpg" href="OPS/image5.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image6_jpg" href="OPS/image6.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image7_jpg" href="OPS/image7.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image8_jpg" href="OPS/image8.jpg" media-type="image/jpeg"/>
|
||||||
|
<myopf:item id="image9_jpg" href="OPS/image9.jpg" media-type="image/jpeg"/>
|
||||||
|
</myopf:manifest>
|
||||||
|
<myopf:spine page-progression-direction="rtl">
|
||||||
|
<myopf:itemref idref="titlepage"/>
|
||||||
|
<myopf:itemref idref="TableOfContents_html"/>
|
||||||
|
<myopf:itemref idref="section-0001_html"/>
|
||||||
|
<myopf:itemref idref="section-0002_html"/>
|
||||||
|
<myopf:itemref idref="section-0003_html"/>
|
||||||
|
<myopf:itemref idref="section-0004_html"/>
|
||||||
|
<myopf:itemref idref="section-0005_html"/>
|
||||||
|
<myopf:itemref idref="section-0006_html"/>
|
||||||
|
<myopf:itemref idref="section-0007_html"/>
|
||||||
|
<myopf:itemref idref="section-0008_html"/>
|
||||||
|
<myopf:itemref idref="section-0009_html"/>
|
||||||
|
<myopf:itemref idref="section-0010_html"/>
|
||||||
|
<myopf:itemref idref="section-0011_html"/>
|
||||||
|
<myopf:itemref idref="section-0012_html"/>
|
||||||
|
<myopf:itemref idref="section-0013_html"/>
|
||||||
|
<myopf:itemref idref="section-0014_html"/>
|
||||||
|
<myopf:itemref idref="section-0015_html"/>
|
||||||
|
<myopf:itemref idref="section-0016_html"/>
|
||||||
|
<myopf:itemref idref="section-0017_html"/>
|
||||||
|
<myopf:itemref idref="section-0018_html"/>
|
||||||
|
<myopf:itemref idref="section-0019_html"/>
|
||||||
|
<myopf:itemref idref="section-0020_html"/>
|
||||||
|
<myopf:itemref idref="section-0021_html"/>
|
||||||
|
<myopf:itemref idref="section-0022_html"/>
|
||||||
|
<myopf:itemref idref="section-0023_html"/>
|
||||||
|
</myopf:spine>
|
||||||
|
</myopf:package>
|
||||||
Loading…
Reference in a new issue