Compare commits

...

114 commits

Author SHA1 Message Date
github-actions[bot]
1c217cbbd4 build(webui): update Browserslist db
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-07-02 12:11:40 +08:00
github-actions
f35f362265 chore(release): 1.25.0 [skip ci] 2026-06-30 07:05:43 +00:00
Gauthier Roebroeck
4efb161ef0 build(openapi): increase timeout for openapi generation
(cherry picked from commit cea20f9cfa)
2026-06-30 14:41:03 +08:00
Gauthier Roebroeck
275cb9251a fix(openapi): flatten hierchical schemas
(cherry picked from commit eb2aa972d5)
2026-06-30 14:40:50 +08:00
Gauthier Roebroeck
bd8b7731dc fix(kobo): enfore content restriction
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
thanks to @5ud0er and @hoangperry
2026-06-25 10:57:45 +08:00
dependabot[bot]
5da5226b35 deps(ci): bump actions/checkout from 6 to 7
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 10:01:18 +08:00
dependabot[bot]
910512c73c deps(webui): bump launch-editor from 2.6.0 to 2.14.1 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [launch-editor](https://github.com/vitejs/launch-editor) from 2.6.0 to 2.14.1.
- [Commits](https://github.com/vitejs/launch-editor/compare/v2.6.0...v2.14.1)

---
updated-dependencies:
- dependency-name: launch-editor
  dependency-version: 2.14.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 09:48:04 +08:00
dependabot[bot]
86362b1ae8 deps(webui): bump axios from 1.15.2 to 1.16.0 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [axios](https://github.com/axios/axios) from 1.15.2 to 1.16.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.15.2...v1.16.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.16.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-01 11:39:09 +08:00
dependabot[bot]
f9f402ed55 deps(webui): bump qs from 6.14.2 to 6.15.2 in /komga-webui
Bumps [qs](https://github.com/ljharb/qs) from 6.14.2 to 6.15.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.2...v6.15.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.15.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-01 11:38:05 +08:00
github-actions[bot]
9a3bbdd878 build(webui): update Browserslist db 2026-06-01 11:37:50 +08:00
dependabot[bot]
3e9a0eaf2c deps(webui): bump js-cookie from 3.0.5 to 3.0.7 in /komga-webui
Some checks failed
Tests / Test webui builds (push) Has been cancelled
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Bumps [js-cookie](https://github.com/js-cookie/js-cookie) from 3.0.5 to 3.0.7.
- [Release notes](https://github.com/js-cookie/js-cookie/releases)
- [Commits](https://github.com/js-cookie/js-cookie/compare/v3.0.5...v3.0.7)

---
updated-dependencies:
- dependency-name: js-cookie
  dependency-version: 3.0.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 09:13:36 +08:00
Gauthier Roebroeck
5682a37d0d feat(komga): add support for solid rar4 archives
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-05-13 10:38:43 +08:00
Gauthier Roebroeck
ba628f9b4e deps(komga): bump junrar to 7.6.0 2026-05-13 10:38:43 +08:00
dependabot[bot]
be5f88c50e deps(webui): bump fast-uri from 3.1.0 to 3.1.2 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.0...v3.1.2)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 09:16:48 +08:00
dependabot[bot]
0bd8edba9d deps(webui): bump @babel/plugin-transform-modules-systemjs
Bumps [@babel/plugin-transform-modules-systemjs](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-modules-systemjs) from 7.22.11 to 7.29.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.4/packages/babel-plugin-transform-modules-systemjs)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-modules-systemjs"
  dependency-version: 7.29.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 09:16:34 +08:00
dependabot[bot]
737cc56d03 deps(webui): bump axios from 1.15.0 to 1.15.2 in /komga-webui
Bumps [axios](https://github.com/axios/axios) from 1.15.0 to 1.15.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.15.0...v1.15.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.15.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 09:14:51 +08:00
github-actions[bot]
ba6cb76b71 build(webui): update Browserslist db
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-05-04 10:04:00 +08:00
Gauthier Roebroeck
3d7615e7b4 deps: upgrade Spring Boot to 3.5.14
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-04-27 17:16:34 +08:00
github-actions
9c84690a07 chore(release): 1.24.4 [skip ci] 2026-04-24 01:52:15 +00:00
Óliver García Albertos
5d14057736
build(docker): update base image to Ubuntu 26.04 for amd64 and arm64
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-04-24 09:14:45 +08:00
James Ward
e3a8cc6b01
fix(api): omit UserDto.ageRestriction instead of returning null
Some checks are pending
Tests / Test server - macos-latest (push) Waiting to run
Tests / Test server - ubuntu-latest (push) Waiting to run
Tests / Test server - windows-latest (push) Waiting to run
Tests / Test webui builds (push) Waiting to run
Closes: 2296
2026-04-23 14:34:05 +08:00
dependabot[bot]
bb60a797e8 deps(webui): bump @xmldom/xmldom from 0.8.12 to 0.8.13 in /komga-webui
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.12 to 0.8.13.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.12...0.8.13)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-23 14:22:19 +08:00
Gauthier Roebroeck
ddfe65dde1 fix(koreader): also accept application/json on Accept header
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-04-21 16:33:45 +08:00
Gauthier Roebroeck
4a7d9a6510 fix(kobo): proxy raw request body to kobo store
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Closes: #2289
2026-04-17 16:45:52 +08:00
dependabot[bot]
85edd8b63f deps(webui): bump axios from 1.13.5 to 1.15.0 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [axios](https://github.com/axios/axios) from 1.13.5 to 1.15.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.5...v1.15.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 14:37:46 +08:00
dependabot[bot]
63de6aa9b1 deps(webui): bump follow-redirects in /komga-webui
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.11 to 1.16.0.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.11...v1.16.0)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 14:37:26 +08:00
Gauthier Roebroeck
717ef82a3d fix(opds2): incorrect latest series navigation links
Closes: #2285
2026-04-14 14:28:54 +08:00
Gauthier Roebroeck
7c00661365 fix(opds2): auth logo issue when using base url
Closes: #2285
2026-04-14 14:28:38 +08:00
Gauthier Roebroeck
6c2621b538 ci: update homebrew action
Some checks are pending
Tests / Test server - macos-latest (push) Waiting to run
Tests / Test server - ubuntu-latest (push) Waiting to run
Tests / Test server - windows-latest (push) Waiting to run
Tests / Test webui builds (push) Waiting to run
2026-04-13 13:22:48 +08:00
Gauthier Roebroeck
5fc0b7ef30 fix(epub): some TOC may not be parsed correctly
Some checks are pending
Tests / Test server - macos-latest (push) Waiting to run
Tests / Test server - ubuntu-latest (push) Waiting to run
Tests / Test server - windows-latest (push) Waiting to run
Tests / Test webui builds (push) Waiting to run
2026-04-13 10:13:35 +08:00
Gauthier Roebroeck
dd9c3facd7 deps: bump gradle-git-properties plugin from 2.5.2 to 2.5.7 2026-04-13 10:13:35 +08:00
dependabot[bot]
b77554fa17 deps(webui): bump lodash from 4.17.23 to 4.18.1 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 11:44:23 +08:00
github-actions[bot]
7e0d680bdf build(webui): update Browserslist db
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
2026-04-01 13:57:47 +08:00
dependabot[bot]
5620e3fd67 deps(webui): bump @xmldom/xmldom from 0.8.10 to 0.8.12 in /komga-webui
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.10 to 0.8.12.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.10...0.8.12)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 09:21:46 +08:00
dependabot[bot]
3ca9806e86 deps(ci): bump gradle/actions from 5 to 6
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [gradle/actions](https://github.com/gradle/actions) from 5 to 6.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/v5...v6)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 15:51:54 +08:00
dependabot[bot]
263d3dd893 deps(webui): bump brace-expansion from 1.1.12 to 1.1.13 in /komga-webui
Some checks are pending
Tests / Test server - macos-latest (push) Waiting to run
Tests / Test server - ubuntu-latest (push) Waiting to run
Tests / Test server - windows-latest (push) Waiting to run
Tests / Test webui builds (push) Waiting to run
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 10:50:15 +08:00
github-actions
328a22064d chore(release): 1.24.3 [skip ci] 2026-03-27 08:39:06 +00:00
dependabot[bot]
40dadcb8ca deps(webui): bump node-forge from 1.3.2 to 1.4.0 in /komga-webui
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.2 to 1.4.0.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.2...v1.4.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-27 16:25:37 +08:00
Gauthier Roebroeck
b8ea79eaf8 fix(webui): epub reader would not load 2026-03-27 16:17:14 +08:00
github-actions
9033dc73ba chore(release): 1.24.2 [skip ci] 2026-03-26 09:43:51 +00:00
Hosted Weblate
da981bed0f i18n(webui): translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/zh_Hans/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
92a61debea i18n(webui): translated using Weblate (Korean)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 안세훈 <on9686@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/ko/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
c00aaebef1 i18n(webui): translated using Weblate (Croatian)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/hr/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
0013a65306 i18n(webui): translated using Weblate (Bulgarian)
Currently translated at 98.6% (829 of 840 strings)

Co-authored-by: A L <lembata1@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/bg/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
df5e90e6e3 i18n(webui): translated using Weblate (German)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Wolfram <kanedat@web.de>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/de/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
c79008d167 i18n(webui): translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (840 of 840 strings)

i18n(webui): translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (840 of 840 strings)

i18n(webui): translated using Weblate (Portuguese (Brazil))

Currently translated at 82.1% (690 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marcos Soares <soaresmarcosb@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/pt_BR/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Hosted Weblate
4fa9422a3d i18n(webui): translated using Weblate (Tamil)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/ta/
Translation: komga/webui
2026-03-26 17:28:16 +08:00
Gauthier Roebroeck
90d3a1dbc3 fix: epub extension could get lost during book restoration 2026-03-26 17:27:28 +08:00
dependabot[bot]
457a7247d5 deps(webui): bump picomatch from 2.3.1 to 2.3.2 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-26 09:57:45 +08:00
dependabot[bot]
de25e4903c deps(ci): bump hydraulic-software/conveyor from 21.1 to 22.0
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [hydraulic-software/conveyor](https://github.com/hydraulic-software/conveyor) from 21.1 to 22.0.
- [Commits](https://github.com/hydraulic-software/conveyor/compare/v21.1...v22.0)

---
updated-dependencies:
- dependency-name: hydraulic-software/conveyor
  dependency-version: '22.0'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 16:15:50 +08:00
dependabot[bot]
b91919a1f5 deps(ci): bump EndBug/add-and-commit from 9 to 10
Bumps [EndBug/add-and-commit](https://github.com/endbug/add-and-commit) from 9 to 10.
- [Release notes](https://github.com/endbug/add-and-commit/releases)
- [Commits](https://github.com/endbug/add-and-commit/compare/v9...v10)

---
updated-dependencies:
- dependency-name: EndBug/add-and-commit
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 16:13:49 +08:00
dependabot[bot]
7ad2bd5c65 deps(webui): bump flatted from 3.2.7 to 3.4.2 in /komga-webui
Some checks failed
Tests / Test server - ubuntu-latest (push) Failing after 4s
Tests / Test webui builds (push) Failing after 4s
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.2.7 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.2.7...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 09:12:52 +08:00
dependabot[bot]
322cf23ad9 deps(webui): bump yauzl and r2-utils-js in /komga-webui
Some checks failed
Tests / Test server - ubuntu-latest (push) Failing after 24s
Tests / Test webui builds (push) Failing after 24s
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Bumps [yauzl](https://github.com/thejoshwolfe/yauzl) and [r2-utils-js](https://github.com/readium/r2-utils-js). These dependencies needed to be updated together.

Updates `yauzl` from 2.10.0 to 3.2.1
- [Commits](https://github.com/thejoshwolfe/yauzl/compare/2.10.0...3.2.1)

Updates `r2-utils-js` from 1.0.35 to 1.0.43
- [Changelog](https://github.com/edrlab/r2-utils-js/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/readium/r2-utils-js/compare/v1.0.35...v1.0.43)

---
updated-dependencies:
- dependency-name: yauzl
  dependency-version: 3.2.1
  dependency-type: indirect
- dependency-name: r2-utils-js
  dependency-version: 1.0.43
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 12:00:10 +08:00
dependabot[bot]
a584f4cf12 deps(ci): bump docker/setup-buildx-action from 3 to 4
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 16:54:01 +08:00
dependabot[bot]
25ccf5a25f deps(ci): bump docker/login-action from 3 to 4
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 16:53:48 +08:00
dependabot[bot]
30ed01505a deps(ci): bump docker/setup-qemu-action from 3 to 4
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 16:53:33 +08:00
dependabot[bot]
fd841253dc deps(webui): bump svgo from 2.8.0 to 2.8.2 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [svgo](https://github.com/svg/svgo) from 2.8.0 to 2.8.2.
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v2.8.0...v2.8.2)

---
updated-dependencies:
- dependency-name: svgo
  dependency-version: 2.8.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 10:58:59 +08:00
dependabot[bot]
112c442af6 deps(webui): bump immutable from 4.3.4 to 4.3.8 in /komga-webui
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 4.3.4 to 4.3.8.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v4.3.4...v4.3.8)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 4.3.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 08:59:35 +08:00
dependabot[bot]
dfdcd08a3c deps(ci): bump actions/upload-artifact from 6 to 7
Some checks failed
Tests / Test webui builds (push) Has been cancelled
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 15:38:01 +08:00
github-actions[bot]
de849a5afd build(webui): update Browserslist db 2026-03-02 13:39:18 +08:00
dependabot[bot]
8b542b86e3 deps(webui): bump minimatch in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps  and [minimatch](https://github.com/isaacs/minimatch). These dependencies needed to be updated together.

Updates `minimatch` from 3.1.2 to 3.1.4
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.4)

Updates `minimatch` from 5.1.6 to 5.1.8
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.4)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.4
  dependency-type: indirect
- dependency-name: minimatch
  dependency-version: 5.1.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-25 12:05:28 +08:00
Gauthier
034ab23b02
docs: rename sponsors 2026-02-25 09:44:25 +08:00
dependabot[bot]
7e83afde10 deps(webui): bump ajv from 6.12.6 to 6.14.0 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.12.6 to 6.14.0.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

---
updated-dependencies:
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 12:12:33 +08:00
dependabot[bot]
3d52eab1bf deps(webui): bump qs from 6.14.1 to 6.14.2 in /komga-webui
Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 11:34:09 +08:00
dependabot[bot]
22fdc2ed0c deps(webui): bump axios from 1.12.0 to 1.13.5 in /komga-webui
Some checks failed
Tests / Test server - macos-latest (push) Has been cancelled
Tests / Test server - ubuntu-latest (push) Has been cancelled
Tests / Test server - windows-latest (push) Has been cancelled
Tests / Test webui builds (push) Has been cancelled
Bumps [axios](https://github.com/axios/axios) from 1.12.0 to 1.13.5.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.12.0...v1.13.5)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.13.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-12 09:59:35 +08:00
dependabot[bot]
0400b8f265 deps(webui): bump webpack from 5.94.0 to 5.105.0 in /komga-webui
Bumps [webpack](https://github.com/webpack/webpack) from 5.94.0 to 5.105.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.94.0...v5.105.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.105.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-06 09:05:22 +08:00
Gauthier Roebroeck
bcc443806a refactor(docker): fix small warnings when builing 2026-02-03 11:14:01 +08:00
Gauthier Roebroeck
45f39b04af fix(docker): remove anonymous /tmp volume
Closes: #2191
2026-02-03 11:12:49 +08:00
github-actions[bot]
6305cae0b5 build(webui): update Browserslist db 2026-02-02 09:36:18 +08:00
Gauthier Roebroeck
4ce8f27707 fix(epub): fallback on epub2 toc if epub3 is present but invalid 2026-01-30 12:26:25 +08:00
github-actions
966dceb10f chore(release): 1.24.1 [skip ci] 2026-01-29 05:05:35 +00:00
Hosted Weblate
80e5432bee i18n(webui): translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/zh_Hans/
Translation: komga/webui
2026-01-29 12:55:41 +08:00
Hosted Weblate
7e2798b2b4 i18n(webui): translated using Weblate (Swedish)
Currently translated at 89.5% (752 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kon K Dong <konkeydong@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/sv/
Translation: komga/webui
2026-01-29 12:55:41 +08:00
Hosted Weblate
deece74f53 i18n(webui): translated using Weblate (Russian)
Currently translated at 55.4% (466 of 840 strings)

i18n(webui): translated using Weblate (Russian)

Currently translated at 64.7% (544 of 840 strings)

Co-authored-by: Aleksey <mitin_aleksey@mail.ru>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/ru/
Translation: komga/webui
2026-01-29 12:55:41 +08:00
Hosted Weblate
f990b9a331 i18n(webui): translated using Weblate (German)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Wolfram <kanedat@web.de>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/de/
Translation: komga/webui
2026-01-29 12:55:41 +08:00
Hosted Weblate
ecf6708e74 i18n(webui): translated using Weblate (Galician)
Currently translated at 24.5% (206 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Johkum <jacobomur@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/gl/
Translation: komga/webui
2026-01-29 12:55:41 +08:00
Gauthier Roebroeck
4f94365735 fix(epub): more lenient fixed-layout detection 2026-01-29 10:36:28 +08:00
github-actions
58cb44583e chore(release): 1.24.0 [skip ci] 2026-01-28 04:06:17 +00:00
Gauthier Roebroeck
512492b72e feat(api): add heartbeat event to SSE connections
Closes: #2205
2026-01-28 11:49:29 +08:00
Gauthier Roebroeck
525b37fce7 feat: support epub with images in spine 2026-01-28 11:32:04 +08:00
dependabot[bot]
a4958b001f deps(webui): bump lodash from 4.17.21 to 4.17.23 in /komga-webui
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-22 10:04:52 +08:00
dependabot[bot]
2ff8ea15b0 deps(ci): bump hydraulic-software/conveyor from 21.0 to 21.1
Bumps [hydraulic-software/conveyor](https://github.com/hydraulic-software/conveyor) from 21.0 to 21.1.
- [Commits](https://github.com/hydraulic-software/conveyor/compare/v21.0...v21.1)

---
updated-dependencies:
- dependency-name: hydraulic-software/conveyor
  dependency-version: '21.1'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-20 09:59:03 +08:00
github-actions[bot]
e6560e0c81 build(webui): update Browserslist db 2026-01-02 10:29:42 +08:00
dependabot[bot]
13761f67ef deps(webui): bump qs from 6.13.0 to 6.14.1 in /komga-webui
Bumps [qs](https://github.com/ljharb/qs) from 6.13.0 to 6.14.1.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-02 10:29:30 +08:00
dependabot[bot]
4911cc8c92 deps(ci): bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 15:06:24 +08:00
dependabot[bot]
2e268b4032 deps(ci): bump dessant/lock-threads from 5 to 6
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 5 to 6.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v5...v6)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 15:06:13 +08:00
Gauthier Roebroeck
62b4154156 deps(webui): update package name for isbn-verify 2025-12-11 13:23:43 +08:00
dependabot[bot]
7d1c9b8cab deps(ci): bump hydraulic-software/conveyor from 20.0 to 21.0
Bumps [hydraulic-software/conveyor](https://github.com/hydraulic-software/conveyor) from 20.0 to 21.0.
- [Commits](https://github.com/hydraulic-software/conveyor/compare/v20.0...v21.0)

---
updated-dependencies:
- dependency-name: hydraulic-software/conveyor
  dependency-version: '21.0'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-08 15:42:28 +08:00
github-actions[bot]
361d20df2c build(webui): update Browserslist db 2025-12-01 11:23:06 +08:00
github-actions
ced89c5c54 chore(release): 1.23.6 [skip ci] 2025-11-28 03:43:03 +00:00
Hosted Weblate
a5548a5429 i18n(komga-tray): translated using Weblate (Arabic)
Currently translated at 100.0% (9 of 9 strings)

i18n(komga-tray): translated using Weblate (Arabic)

Currently translated at 33.3% (3 of 9 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: redaloe <farahks@proton.me>
Co-authored-by: redaloe <redaloe@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/desktop/ar/
Translation: komga/desktop
2025-11-28 11:11:17 +08:00
Hosted Weblate
8f8d20a324 i18n(komga-tray): translated using Weblate (Russian)
Currently translated at 77.7% (7 of 9 strings)

Co-authored-by: Aleksey <mitin_aleksey@mail.ru>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/desktop/ru/
Translation: komga/desktop
2025-11-28 11:11:17 +08:00
Hosted Weblate
0f69a3a4cb i18n(komga-tray): translated using Weblate (Galician)
Currently translated at 100.0% (9 of 9 strings)

Co-authored-by: Francisco José Aquino García <fj.aquino@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/komga/desktop/gl/
Translation: komga/desktop
2025-11-28 11:11:17 +08:00
Hosted Weblate
9d10ed31a7 chore: update translation files
Updated by "Remove blank strings" hook in Weblate.

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

i18n(webui): translated using Weblate (Arabic)

Currently translated at 91.6% (770 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Weblate Translation Memory <noreply-mt-weblate-translation-memory@weblate.org>
Co-authored-by: redaloe <redaloe@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/
Translate-URL: https://hosted.weblate.org/projects/komga/webui/ar/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Hosted Weblate
dde0169f2a i18n(webui): translated using Weblate (Croatian)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/hr/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Hosted Weblate
a2ed7d319d i18n(webui): translated using Weblate (Russian)
Currently translated at 64.6% (543 of 840 strings)

i18n(webui): translated using Weblate (Russian)

Currently translated at 67.0% (563 of 840 strings)

Co-authored-by: Aleksey <mitin_aleksey@mail.ru>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/ru/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Hosted Weblate
475f026749 i18n(webui): translated using Weblate (Portuguese (Brazil))
Currently translated at 79.5% (668 of 840 strings)

i18n(webui): translated using Weblate (Portuguese (Brazil))

Currently translated at 79.5% (668 of 840 strings)

i18n(webui): translated using Weblate (Portuguese (Brazil))

Currently translated at 79.5% (668 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Luiz Henrique Moreira de Souza <cloud.5623tumacacori@gmail.com>
Co-authored-by: Weblate Translation Memory <noreply-mt-weblate-translation-memory@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/pt_BR/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Hosted Weblate
a03f1bdf7b i18n(webui): translated using Weblate (Thai)
Currently translated at 100.0% (840 of 840 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: altinat <al@altqx.com>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/th/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Hosted Weblate
b43046fbeb chore: update translation files
Updated by "Remove blank strings" hook in Weblate.

i18n(webui): translated using Weblate (Galician)

Currently translated at 20.1% (169 of 840 strings)

Co-authored-by: Francisco José Aquino García <fj.aquino@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/komga/webui/
Translate-URL: https://hosted.weblate.org/projects/komga/webui/gl/
Translation: komga/webui
2025-11-28 11:10:47 +08:00
Jason
3739951b36
fix(kobo): proxy 401 errors on initialization
Co-authored-by: Gauthier Roebroeck <gauthier.roebroeck@gmail.com>
2025-11-28 11:10:01 +08:00
dependabot[bot]
0f25453949 deps(webui): bump node-forge from 1.3.1 to 1.3.2 in /komga-webui
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.2.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-27 11:02:30 +08:00
dependabot[bot]
cd47fc777a deps(webui): bump js-yaml from 3.14.1 to 3.14.2 in /komga-webui
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.14.1 to 3.14.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...3.14.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 3.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 16:07:21 +08:00
dependabot[bot]
f138fe31e7 deps(ci): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 15:39:11 +08:00
Jason
454c6c7202
refactor(kobo): log error responses 2025-11-13 13:32:16 +08:00
Jason
ce3ad4c1c7
fix(kobo): prevent double URL encoding when proxying
Closes: #2130
2025-11-11 15:52:32 +08:00
Jason
b925f3e19d
fix(kobo): proxy Content-Type headers for kobo
Closes: #2074
2025-11-10 15:26:07 +08:00
Gauthier Roebroeck
9a56b30b6c ci: fix svu install 2025-11-03 16:00:14 +08:00
dependabot[bot]
6b07fda273 deps(ci): bump mikepenz/action-junit-report from 5 to 6
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 5 to 6.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/v5...v6)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-03 15:12:21 +08:00
github-actions[bot]
727fe39e6d build(webui): update Browserslist db 2025-11-03 10:39:12 +08:00
Gauthier Roebroeck
f8ca936ee7 fix: properly decode cover href when generating epub cover
Closes: #2118
2025-11-03 10:38:43 +08:00
dependabot[bot]
fe40ede34a deps(ci): bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-28 10:46:45 +08:00
dependabot[bot]
c23f2d3810 deps(ci): bump actions/setup-node from 5 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 15:51:56 +08:00
Gauthier Roebroeck
af66144060 docs(api): fix mediatype 2025-10-14 14:00:34 +08:00
Gauthier Roebroeck
ba7b82631f build(docker): use old-releases apt repo 2025-10-08 16:42:12 +08:00
58 changed files with 5784 additions and 3326 deletions

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Configure git

View file

@ -12,7 +12,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@v6
with:
github-token: ${{ github.token }}
issue-inactive-days: '30'

View file

@ -43,14 +43,14 @@ jobs:
version_next: ${{ steps.versions.outputs.version_next }}
should_release: ${{ steps.versions.outputs.should_release }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
uses: Homebrew/actions/setup-homebrew@main
- name: Install svu
run: brew install caarlos0/tap/svu
run: brew install --cask caarlos0/tap/svu
- name: Compute next version for release
run: |
echo "VERSION_NEXT=`svu ${{ inputs.bump }}`" | tee -a $GITHUB_ENV
@ -72,7 +72,7 @@ jobs:
sudo rm -rf /usr/share/dotnet
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
fetch-depth: 0
@ -84,7 +84,7 @@ jobs:
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
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@ -98,26 +98,26 @@ jobs:
distribution: 'temurin'
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
uses: gradle/actions/setup-gradle@v6
- name: Build
run: ./gradlew :komga:prepareThymeLeaf :komga:bootJar :komga-tray:jar
@ -143,7 +143,7 @@ jobs:
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: JReleaser Changelog output
if: always() && needs.version.outputs.should_release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: jreleaser-changelog
path: |
@ -151,7 +151,7 @@ jobs:
build/jreleaser/output.properties
- name: Release commit and push
uses: EndBug/add-and-commit@v9
uses: EndBug/add-and-commit@v10
if: needs.version.outputs.should_release #only redo if the version changed
with:
message: 'chore(release): ${{ needs.version.outputs.version_next }} [skip ci]'
@ -167,7 +167,7 @@ jobs:
echo $APPLE_PRIVATE_KEY | base64 --decode > ./secret/apple_private_key.p8
- name: Conveyor make copied-site
uses: hydraulic-software/conveyor/actions/build@v20.0
uses: hydraulic-software/conveyor/actions/build@v22.0
if: inputs.conveyor-copied-site
with:
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 }}
- name: Upload Conveyor log
if: always() && inputs.conveyor-copied-site
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: conveyor-make-copied-site
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt
@ -194,7 +194,7 @@ jobs:
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: JReleaser Release output
if: always() && inputs.github_release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: jreleaser-release
path: |
@ -212,7 +212,7 @@ jobs:
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: JReleaser Publish output
if: always() && inputs.docker_release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: jreleaser-publish
path: |
@ -220,7 +220,7 @@ jobs:
build/jreleaser/output.properties
- name: Conveyor - publish to Microsoft Store
uses: hydraulic-software/conveyor/actions/build@v20.0
uses: hydraulic-software/conveyor/actions/build@v22.0
if: inputs.msstore_release
with:
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 }}
- name: Upload Conveyor log
if: always() && inputs.msstore_release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: conveyor-ms-store-release
path: ~/.cache/hydraulic/conveyor/logs/log.latest.txt

View file

@ -19,7 +19,7 @@ jobs:
fail-fast: false
name: Test server - ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- name: Setup Java 21
uses: actions/setup-java@v5
with:
@ -28,27 +28,27 @@ jobs:
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
uses: gradle/actions/setup-gradle@v6
- name: Build
run: ./gradlew build :komga-tray:jar
- name: Upload Unit Test Results
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: test-results-${{ matrix.os }}
path: komga/build/test-results/
- name: Upload Unit Test Reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: test-reports-${{ matrix.os }}
path: komga/build/reports/tests/
- name: Publish Test Report
uses: mikepenz/action-junit-report@v5
uses: mikepenz/action-junit-report@v6
if: always()
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
@ -56,7 +56,7 @@ jobs:
- name: Conveyor - compute JDK module list
if: github.event_name == 'push' && github.repository_owner == 'gotson' && contains(matrix.os, 'ubuntu')
uses: hydraulic-software/conveyor/actions/build@v20.0
uses: hydraulic-software/conveyor/actions/build@v22.0
with:
command: -f conveyor.detect.conf -Kapp.machines=mac.aarch64 make processed-jars
signing_key: ${{ secrets.CONVEYOR_SIGNING_KEY }}
@ -69,7 +69,7 @@ jobs:
- name: Upload JDK required modules
if: steps.conveyor_compare.outcome == 'failure'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: conveyor-required-jdk-modules
path: ./output/required-jdk-modules.txt
@ -78,8 +78,8 @@ jobs:
runs-on: ubuntu-latest
name: Test webui builds
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'

View file

@ -1,3 +1,238 @@
# [1.25.0](https://github.com/gotson/komga/compare/1.24.4...1.25.0) (2026-06-30)
## 🚀 Features
**komga**
- add support for solid rar4 archives ([5682a37](https://github.com/gotson/komga/commits/5682a37))
## 🐛 Fixes
**kobo**
- enfore content restriction ([bd8b773](https://github.com/gotson/komga/commits/bd8b773))
**openapi**
- flatten hierchical schemas ([275cb92](https://github.com/gotson/komga/commits/275cb92))
## 🛠 Build
**openapi**
- increase timeout for openapi generation ([4efb161](https://github.com/gotson/komga/commits/4efb161))
**webui**
- update Browserslist db ([9a3bbdd](https://github.com/gotson/komga/commits/9a3bbdd))
- update Browserslist db ([ba6cb76](https://github.com/gotson/komga/commits/ba6cb76))
## ⚙️ Dependencies
**ci**
- bump actions/checkout from 6 to 7 ([5da5226](https://github.com/gotson/komga/commits/5da5226))
**komga**
- bump junrar to 7.6.0 ([ba628f9](https://github.com/gotson/komga/commits/ba628f9))
**webui**
- bump launch-editor from 2.6.0 to 2.14.1 in /komga-webui ([910512c](https://github.com/gotson/komga/commits/910512c))
- bump axios from 1.15.2 to 1.16.0 in /komga-webui ([86362b1](https://github.com/gotson/komga/commits/86362b1))
- bump qs from 6.14.2 to 6.15.2 in /komga-webui ([f9f402e](https://github.com/gotson/komga/commits/f9f402e))
- bump js-cookie from 3.0.5 to 3.0.7 in /komga-webui ([3e9a0ea](https://github.com/gotson/komga/commits/3e9a0ea))
- bump fast-uri from 3.1.0 to 3.1.2 in /komga-webui ([be5f88c](https://github.com/gotson/komga/commits/be5f88c))
- bump @babel/plugin-transform-modules-systemjs ([0bd8edb](https://github.com/gotson/komga/commits/0bd8edb))
- bump axios from 1.15.0 to 1.15.2 in /komga-webui ([737cc56](https://github.com/gotson/komga/commits/737cc56))
**unscoped**
- upgrade Spring Boot to 3.5.14 ([3d7615e](https://github.com/gotson/komga/commits/3d7615e))
# [1.24.4](https://github.com/gotson/komga/compare/1.24.3...1.24.4) (2026-04-24)
## 🐛 Fixes
**api**
- omit UserDto.ageRestriction instead of returning null ([e3a8cc6](https://github.com/gotson/komga/commits/e3a8cc6))
**epub**
- some TOC may not be parsed correctly ([5fc0b7e](https://github.com/gotson/komga/commits/5fc0b7e))
**kobo**
- proxy raw request body to kobo store ([4a7d9a6](https://github.com/gotson/komga/commits/4a7d9a6)), closes [#2289](https://github.com/gotson/komga/issues/2289)
**koreader**
- also accept application/json on Accept header ([ddfe65d](https://github.com/gotson/komga/commits/ddfe65d))
**opds2**
- incorrect latest series navigation links ([717ef82](https://github.com/gotson/komga/commits/717ef82)), closes [#2285](https://github.com/gotson/komga/issues/2285)
- auth logo issue when using base url ([7c00661](https://github.com/gotson/komga/commits/7c00661)), closes [#2285](https://github.com/gotson/komga/issues/2285)
## 🛠 Build
**docker**
- update base image to Ubuntu 26.04 for amd64 and arm64 ([5d14057](https://github.com/gotson/komga/commits/5d14057))
**webui**
- update Browserslist db ([7e0d680](https://github.com/gotson/komga/commits/7e0d680))
**unscoped**
- update homebrew action ([6c2621b](https://github.com/gotson/komga/commits/6c2621b))
## ⚙️ Dependencies
**ci**
- bump gradle/actions from 5 to 6 ([3ca9806](https://github.com/gotson/komga/commits/3ca9806))
**webui**
- bump @xmldom/xmldom from 0.8.12 to 0.8.13 in /komga-webui ([bb60a79](https://github.com/gotson/komga/commits/bb60a79))
- bump axios from 1.13.5 to 1.15.0 in /komga-webui ([85edd8b](https://github.com/gotson/komga/commits/85edd8b))
- bump follow-redirects in /komga-webui ([63de6aa](https://github.com/gotson/komga/commits/63de6aa))
- bump lodash from 4.17.23 to 4.18.1 in /komga-webui ([b77554f](https://github.com/gotson/komga/commits/b77554f))
- bump @xmldom/xmldom from 0.8.10 to 0.8.12 in /komga-webui ([5620e3f](https://github.com/gotson/komga/commits/5620e3f))
- bump brace-expansion from 1.1.12 to 1.1.13 in /komga-webui ([263d3dd](https://github.com/gotson/komga/commits/263d3dd))
**unscoped**
- bump gradle-git-properties plugin from 2.5.2 to 2.5.7 ([dd9c3fa](https://github.com/gotson/komga/commits/dd9c3fa))
# [1.24.3](https://github.com/gotson/komga/compare/1.24.2...1.24.3) (2026-03-27)
## 🐛 Fixes
**webui**
- epub reader would not load ([b8ea79e](https://github.com/gotson/komga/commits/b8ea79e))
## ⚙️ Dependencies
**webui**
- bump node-forge from 1.3.2 to 1.4.0 in /komga-webui ([40dadcb](https://github.com/gotson/komga/commits/40dadcb))
# [1.24.2](https://github.com/gotson/komga/compare/1.24.1...1.24.2) (2026-03-26)
## 🐛 Fixes
**docker**
- remove anonymous /tmp volume ([45f39b0](https://github.com/gotson/komga/commits/45f39b0)), closes [#2191](https://github.com/gotson/komga/issues/2191)
**epub**
- fallback on epub2 toc if epub3 is present but invalid ([4ce8f27](https://github.com/gotson/komga/commits/4ce8f27))
**unscoped**
- epub extension could get lost during book restoration ([90d3a1d](https://github.com/gotson/komga/commits/90d3a1d))
## 🔄️ Changes
**docker**
- fix small warnings when builing ([bcc4438](https://github.com/gotson/komga/commits/bcc4438))
## 🛠 Build
**webui**
- update Browserslist db ([de849a5](https://github.com/gotson/komga/commits/de849a5))
- update Browserslist db ([6305cae](https://github.com/gotson/komga/commits/6305cae))
## 📝 Documentation
- rename sponsors ([034ab23](https://github.com/gotson/komga/commits/034ab23))
## 🌐 Translation
**webui**
- translated using Weblate (Chinese (Simplified Han script)) ([da981be](https://github.com/gotson/komga/commits/da981be))
- translated using Weblate (Korean) ([92a61de](https://github.com/gotson/komga/commits/92a61de))
- translated using Weblate (Croatian) ([c00aaeb](https://github.com/gotson/komga/commits/c00aaeb))
- translated using Weblate (Bulgarian) ([0013a65](https://github.com/gotson/komga/commits/0013a65))
- translated using Weblate (German) ([df5e90e](https://github.com/gotson/komga/commits/df5e90e))
- translated using Weblate (Portuguese (Brazil)) ([c79008d](https://github.com/gotson/komga/commits/c79008d))
- translated using Weblate (Tamil) ([4fa9422](https://github.com/gotson/komga/commits/4fa9422))
## ⚙️ Dependencies
**ci**
- bump hydraulic-software/conveyor from 21.1 to 22.0 ([de25e49](https://github.com/gotson/komga/commits/de25e49))
- bump EndBug/add-and-commit from 9 to 10 ([b91919a](https://github.com/gotson/komga/commits/b91919a))
- bump docker/setup-buildx-action from 3 to 4 ([a584f4c](https://github.com/gotson/komga/commits/a584f4c))
- bump docker/login-action from 3 to 4 ([25ccf5a](https://github.com/gotson/komga/commits/25ccf5a))
- bump docker/setup-qemu-action from 3 to 4 ([30ed015](https://github.com/gotson/komga/commits/30ed015))
- bump actions/upload-artifact from 6 to 7 ([dfdcd08](https://github.com/gotson/komga/commits/dfdcd08))
**webui**
- bump picomatch from 2.3.1 to 2.3.2 in /komga-webui ([457a724](https://github.com/gotson/komga/commits/457a724))
- bump flatted from 3.2.7 to 3.4.2 in /komga-webui ([7ad2bd5](https://github.com/gotson/komga/commits/7ad2bd5))
- bump yauzl and r2-utils-js in /komga-webui ([322cf23](https://github.com/gotson/komga/commits/322cf23))
- bump svgo from 2.8.0 to 2.8.2 in /komga-webui ([fd84125](https://github.com/gotson/komga/commits/fd84125))
- bump immutable from 4.3.4 to 4.3.8 in /komga-webui ([112c442](https://github.com/gotson/komga/commits/112c442))
- bump minimatch in /komga-webui ([8b542b8](https://github.com/gotson/komga/commits/8b542b8))
- bump ajv from 6.12.6 to 6.14.0 in /komga-webui ([7e83afd](https://github.com/gotson/komga/commits/7e83afd))
- bump qs from 6.14.1 to 6.14.2 in /komga-webui ([3d52eab](https://github.com/gotson/komga/commits/3d52eab))
- bump axios from 1.12.0 to 1.13.5 in /komga-webui ([22fdc2e](https://github.com/gotson/komga/commits/22fdc2e))
- bump webpack from 5.94.0 to 5.105.0 in /komga-webui ([0400b8f](https://github.com/gotson/komga/commits/0400b8f))
# [1.24.1](https://github.com/gotson/komga/compare/1.24.0...1.24.1) (2026-01-29)
## 🐛 Fixes
**epub**
- more lenient fixed-layout detection ([4f94365](https://github.com/gotson/komga/commits/4f94365))
## 🌐 Translation
**webui**
- translated using Weblate (Chinese (Simplified Han script)) ([80e5432](https://github.com/gotson/komga/commits/80e5432))
- translated using Weblate (Swedish) ([7e2798b](https://github.com/gotson/komga/commits/7e2798b))
- translated using Weblate (Russian) ([deece74](https://github.com/gotson/komga/commits/deece74))
- translated using Weblate (German) ([f990b9a](https://github.com/gotson/komga/commits/f990b9a))
- translated using Weblate (Galician) ([ecf6708](https://github.com/gotson/komga/commits/ecf6708))
# [1.24.0](https://github.com/gotson/komga/compare/1.23.6...1.24.0) (2026-01-28)
## 🚀 Features
**api**
- add heartbeat event to SSE connections ([512492b](https://github.com/gotson/komga/commits/512492b)), closes [#2205](https://github.com/gotson/komga/issues/2205)
**unscoped**
- support epub with images in spine ([525b37f](https://github.com/gotson/komga/commits/525b37f))
## 🛠 Build
**webui**
- update Browserslist db ([e6560e0](https://github.com/gotson/komga/commits/e6560e0))
- update Browserslist db ([361d20d](https://github.com/gotson/komga/commits/361d20d))
## ⚙️ Dependencies
**ci**
- bump hydraulic-software/conveyor from 21.0 to 21.1 ([2ff8ea1](https://github.com/gotson/komga/commits/2ff8ea1))
- bump actions/upload-artifact from 5 to 6 ([4911cc8](https://github.com/gotson/komga/commits/4911cc8))
- bump dessant/lock-threads from 5 to 6 ([2e268b4](https://github.com/gotson/komga/commits/2e268b4))
- bump hydraulic-software/conveyor from 20.0 to 21.0 ([7d1c9b8](https://github.com/gotson/komga/commits/7d1c9b8))
**webui**
- bump lodash from 4.17.21 to 4.17.23 in /komga-webui ([a4958b0](https://github.com/gotson/komga/commits/a4958b0))
- bump qs from 6.13.0 to 6.14.1 in /komga-webui ([13761f6](https://github.com/gotson/komga/commits/13761f6))
- update package name for isbn-verify ([62b4154](https://github.com/gotson/komga/commits/62b4154))
# [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

View file

@ -47,7 +47,7 @@ Check the [development guidelines](./DEVELOPING.md).
[![Translation status](https://hosted.weblate.org/widgets/komga/-/webui/horizontal-auto.svg)](https://hosted.weblate.org/engage/komga/)
## Sponsors
## Powered by
[![Jetbrains_logo](./.github/readme-images/jetbrains.svg)](https://www.jetbrains.com/?from=Komga)

View file

@ -1,2 +1,2 @@
version=1.23.5
version=1.25.0
org.gradle.jvmargs=-Xmx2G

View file

@ -2,9 +2,9 @@
sqliteJdbc = "3.50.2.0"
nightmonkeys = "1.0.0"
twelvemonkeys = "3.12.0"
springboot = "3.5.4"
springboot = "3.5.14"
lucene = "9.9.1" # v10 requires JDK 21
jooq = "3.19.24" # should be aligned with the version provided by Spring Boot
jooq = "3.19.32" # should be aligned with the version provided by Spring Boot
[plugins]
gradleGitProperties = {id = "com.gorylenko.gradle-git-properties", version = "2.5.2"}
gradleGitProperties = {id = "com.gorylenko.gradle-git-properties", version = "2.5.7"}

View file

@ -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=إظهار ملف السجل

View file

@ -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

View file

@ -1,7 +1,7 @@
dialog_error.close=Закрыть
dialog_error.copy_clipboard=Скопировать в буфер обмена
dialog_error.title=Komga не смог запуститься
error_message.port_in_use=Порт {] уже используется.\nKomga возможно уже работает.\nПроверьте панель задач или меню на наличие иконки Komga.
dialog_error.title=Komga не удалось запустить
error_message.port_in_use=Порт {} уже используется.\nВероятно, Komga уже запущен.\nПроверьте область уведомлений или панель меню на наличие иконки Komga.
error_message.unexpected=Произошла непредвиденная ошибка.
menu.open_komga=Открыть Komga
menu.quit=Закрыть Komga

File diff suppressed because it is too large Load diff

View file

@ -10,17 +10,17 @@
},
"dependencies": {
"@d-i-t-a/reader": "github:gotson/R2D2BC#fork",
"@saekitominaga/isbn-verify": "^2.0.1",
"axios": "^1.12.0",
"@w0s/isbn-verify": "^3.1.2",
"axios": "^1.16.0",
"chart.js": "^2.9.4",
"core-js": "^3.8.3",
"date-fns": "^2.30.0",
"filesize": "^10.0.12",
"js-file-downloader": "^1.1.25",
"language-tags": "^1.0.9",
"lodash": "^4.17.21",
"lodash": "^4.18.1",
"marked": "^15.0.4",
"qs": "^6.11.2",
"qs": "^6.15.2",
"screenfull": "^5.2.0",
"vue": "^2.6.14",
"vue-chartkick": "^0.6.1",

View file

@ -200,7 +200,7 @@
<script lang="ts">
import Vue from 'vue'
import {BookDto} from '@/types/komga-books'
import IsbnVerify from '@saekitominaga/isbn-verify'
import IsbnVerify from '@w0s/isbn-verify'
import {isMatch} from 'date-fns'
import {ERROR} from '@/types/events'

View file

@ -430,7 +430,7 @@ import {authorRoles} from '@/types/author-roles'
import Vue from 'vue'
import {helpers, requiredIf} from 'vuelidate/lib/validators'
import {BookDto, BookThumbnailDto} from '@/types/komga-books'
import IsbnVerify from '@saekitominaga/isbn-verify'
import IsbnVerify from '@w0s/isbn-verify'
import {isMatch} from 'date-fns'
import {debounce} from 'lodash'
import {ERROR, ErrorEvent} from '@/types/events'

View file

@ -570,7 +570,7 @@ import DropZone from '@/components/DropZone.vue'
import ThumbnailCard from '@/components/ThumbnailCard.vue'
import {BookDto, BookThumbnailDto} from '@/types/komga-books'
import {isMatch} from 'date-fns'
import IsbnVerify from '@saekitominaga/isbn-verify'
import IsbnVerify from '@w0s/isbn-verify'
import {debounce} from 'lodash'
import {authorRoles} from '@/types/author-roles'
import {groupAuthorsByRole} from '@/functions/authors'

View file

@ -19,7 +19,15 @@
},
"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": {
"mark_all_read": "اشر عليها بانها قرأت",
@ -27,6 +35,7 @@
"tab_title": "إعلانات"
},
"authentication_activity": {
"api_key": "مفتاح API",
"datetime": "التاريخ والوقت",
"email": "البريد الإلكتروني",
"error": "خطأ",
@ -85,7 +94,8 @@
"bookreader": {
"beginning_of_book": "أنت في بداية الكتاب.",
"changing_reading_direction": "تغيير اتجاه القراءة إلى",
"cycling_page_layout": "تخطيط دوري للصفحة",
"cycling_page_layout": "تغيير تخطيط الصفحة",
"cycling_page_margin": "تغيير هامش الصفحة",
"cycling_scale": "تغيير حجم التحرير",
"cycling_side_padding": "تغيير الحدود الجانبية",
"download_current_page": "تنزيل الصفحة الحالية",
@ -128,6 +138,7 @@
"general": "إعدادات عامة",
"gestures": "الإيماءات",
"page_layout": "تخطيط الصفحة",
"page_margin": "هامش الصفحة",
"paged": "خيارات القارئ المرقم",
"reading_mode": "وضع القراءة",
"scale_type": "نوع القياس",
@ -137,8 +148,9 @@
},
"shortcuts": {
"close": "إغلاق",
"cycle_page_layout": "دورة تخطيط الصفحة",
"cycle_scale": "مقياس الدورة",
"cycle_page_layout": "تغيير تخطيط الصفحة",
"cycle_page_margin": "تغيير هامش الصفحة",
"cycle_scale": "تغيير الحجم",
"cycle_side_padding": "تغيير الحدود الجانبية",
"first_page": "الصفحة الأولى",
"fullscreen": "إدخال/إنهاء ملء الشاشة",
@ -161,6 +173,8 @@
},
"browse_book": {
"comment": "تعليق",
"date_created": "صُنِع",
"date_modified": "آخر تعديل",
"download_file": "تحميل الملف",
"file": "ملف",
"format": "صيغة",
@ -170,6 +184,8 @@
"outdated_tooltip": "تم تغيير ملف هذا الكتاب ، يجب إعادة تحليل هذا الكتاب",
"read_book": "قراءة كتاب",
"read_incognito": "قراءة التصفح المتخفي",
"remove_from_collection": "إزالة الكتاب من المجموعة",
"remove_from_readlist": "إزالة الكتاب من قائمة القراءة",
"size": "حجم"
},
"browse_collection": {
@ -184,6 +200,7 @@
},
"browse_series": {
"earliest_year_from_release_dates": "هذه هي السنة الأولى من تواريخ الإصدار لجميع الكتب في السلسلة",
"remove_from_collection": "إزالة السلسلة من المجموعة",
"series_no_summary": "هذه السلسلة لا تحتوي على ملخص ، لذلك اخترنا واحدًا لك!",
"summary_from_book": "ملخص من الكتاب {number}:"
},
@ -194,6 +211,8 @@
"common": {
"age": "العمر",
"all_libraries": "كل المكتبات",
"all_of": "كل من",
"any_of": "أي من",
"book": "كتاب",
"books": "كتب",
"books_n": "لا يوجد كتاب | 1 كتاب | {count} كتب",
@ -203,15 +222,19 @@
"choose_image": "اختر صورة",
"close": "إغلاق",
"collections": "المجموعات",
"copied": "تم النسخ!",
"create": "صنع",
"delete": "حذف",
"discard": "تجاهل",
"dimension": "ع:{width}, ط:{height}",
"discard": "تخلص",
"disk_space": "مساحة القرص",
"dismiss": "رفض",
"download": "تحميل",
"drag_drop": "أمسك واسحب",
"duplicate": "مكرر",
"email": "البريد الإلكتروني",
"epub": "Epub",
"epub": "EPUB",
"error": "خطأ",
"filename": "اسم الملف",
"filter_no_matches": "الفلتر النشط ليس له تطابق",
"genre": "نوع",
@ -219,13 +242,17 @@
"go_to_library": "اذهب إلى المكتبة",
"go_to_readlist": "انتقل إلى قائمة القراءة",
"go_to_series": "الانتقال إلى السلسلة",
"i_understand": "فهمت",
"library": "مكتبة",
"locale_name": "العربية",
"locale_rtl": "true",
"lock_all": "قفل الكل",
"media": "الوسائط",
"more": "المزيد",
"n_selected": "{count} مختار",
"nothing_to_show": "لا شيء للعرض",
"oneshot": "طلقة واحدة",
"ok": "حسنا",
"oneshot": "قصة منفردة",
"outdated": "متقادمة",
"page": "صفحة",
"page_number": "رقم الصفحة",
@ -235,19 +262,23 @@
"password": "كلمة السر",
"pdf": "PDF",
"pending_tasks": "لا توجد مهام معلقة | مهمة واحدة معلقة | {count} مهام معلقة",
"pinned_libraries": "المكتبات المثبتة",
"publisher": "الناشر",
"read": "اقرأ",
"read_on": "قرأ في {date}",
"readlist": "قائمة القراءة",
"readlists": "قوائم القراءة",
"remember-me": "تذكرني",
"reorder": "تغيير الترتيب",
"required": "مطلوب",
"reset_filters": "إعادة تعيين فلتر",
"roles": "أدوار",
"save_changes": "حفظ التغييرات",
"series": "سلسلة",
"settings": "الإعدادات",
"sidecars": "Sidecars",
"tags": "التصنيف",
"ui": "واجهة المستخدم",
"unavailable": "غير متوفر",
"unlock_all": "فتح الكل",
"url": "عنوان URL",
@ -271,10 +302,11 @@
"comicrack_preambule_html": "يمكنك استيراد قوائم قراءة ComicRack الحالية بتنسيق <code>cbl</code>.<br>سيحاول Komga مطابقة السلسلة ورقم الكتاب المقدمين مع السلسلة والكتب في مكتباتك.",
"dialog_confirmation": {
"body": "{unmatched} / {total} الكتب غير متطابقة",
"body2": "{duplicates} / {total} كتاب مكرر",
"create": "الخلق على أي حال",
"title": "بعض الكتب لا تتطابق"
},
"field_file_label": "ComicRack Reading List (.cbl)",
"field_file_label": "قائمة قراءة ComicRack (من نوع cbl.)",
"field_files_label": "قوائم القراءة ComicRack (.cbl)",
"import_read_lists": "استيراد قوائم القراءة",
"imported_as": "مستورد كـ {name}",
@ -286,6 +318,14 @@
"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} سلسلة",
@ -319,6 +359,12 @@
"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}\" وملفاته",
@ -389,6 +435,8 @@
"field_summary": "ملخص",
"field_tags": "التصنيف",
"field_title": "العنوان",
"number_sort_decrement": "تقليل الجميع ب1",
"number_sort_increment": "زيادة الجميع ب1",
"tab_authors": "المؤلفون",
"tab_general": "إعدادات عامة",
"tab_links": "الروابط",
@ -415,6 +463,7 @@
"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": "الباركود ردمك",
@ -422,15 +471,19 @@
"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": "‬موقع القصص المنفردة",
"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": "المجلد الجذر للمكتبة",
@ -441,11 +494,14 @@
"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 Drive",
"tooltip_use_resources": "يمكن أن تستهلك الكثير من الموارد في مكتبات كبيرة أو أجهزة بطيئة"
},
@ -453,11 +509,16 @@
"button_cancel": "إلغاء",
"button_confirm": "حفظ التغييرات",
"dialog_title": "تحرير قائمة القراءة",
"field_manual_ordering": "ترتيب يدوي",
"field_name": "الاسم",
"field_summary": "ملخص",
"tab_general": "عام",
"tab_poster": "ملصق"
},
"edit_recommended": {
"button_confirm": "حفظ التعديلات",
"button_reset": "الإعادة إلى التعديلات الأصلية"
},
"edit_series": {
"button_cancel": "إلغاء",
"button_confirm": "حفظ التغييرات",
@ -483,6 +544,7 @@
"tab_poster": "ملصق",
"tab_sharing": "مشاركة",
"tab_tags": "التصنيف",
"tab_titles": "العناوين البديلة",
"tags_notice_multiple_edit": "أنت تقوم بتحرير العلامات لسلسلة متعددة. سيؤدي هذا إلى تجاوز العلامات الموجودة في كل سلسلة."
},
"edit_user": {
@ -525,6 +587,9 @@
},
"title": "اسم الوجهة"
},
"force_kobo_sync": {
"dialog_title": "إجبار مزامنة Kobo"
},
"password_change": {
"button_cancel": "إلغاء",
"button_confirm": "تغيير كلمة السر",
@ -541,6 +606,7 @@
},
"series_picker": {
"label_search_series": "سلسلة البحث",
"no_results": "لم يتم العثور على أي سلسلة",
"title": "اختيار سلسلة"
},
"server_stop": {
@ -579,21 +645,31 @@
}
},
"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})",
"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": "حجم مجهول"
@ -609,6 +685,23 @@
"HARDLINK": "ملفات الروابط الثابتة/النسخ",
"MOVE": "نقل الملفات"
},
"epubreader": {
"appearances": {
"day": "النهار",
"night": "الليل",
"sepia": "سيبيا"
},
"column_count": {
"auto": "أوتوماتيكي",
"one": "واحد",
"two": "اثنان"
},
"reading_direction": {
"auto": "أوتوماتيكي",
"ltr": "من اليسار إلى اليمين",
"rtl": "من اليمين إلى اليسار"
}
},
"historical_event_type": {
"BookConverted": "تمّ تحويل الكتاب",
"BookFileDeleted": "تمّ مسح ملف الكتاب",
@ -616,6 +709,11 @@
"DuplicatePageDeleted": "تمّ حذف الصفحة المكررة",
"SeriesFolderDeleted": "تمّ حذف مجلد السلسلة"
},
"media_profile": {
"DIVINA": "DIVINA",
"EPUB": "EPUB",
"PDF": "PDF"
},
"media_status": {
"ERROR": "خطأ",
"OUTDATED": "قديمه",
@ -634,6 +732,14 @@
"VERTICAL": "عمودي",
"WEBTOON": "ويبتون"
},
"scan_interval": {
"DAILY": "يوميا",
"DISABLED": "معطل",
"EVERY_12H": "كل 12 ساعة",
"EVERY_6H": "كل 6 ساعات",
"HOURLY": "كل ساعة",
"WEEKLY": "كل أسبوع"
},
"series_cover": {
"FIRST": "أول",
"LAST": "أخير"
@ -645,6 +751,34 @@
"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": {
"ERR_1000": "تعذر الوصول إلى الملف أثناء التحليل",
"ERR_1001": "نوع الوسائط غير مدعوم",
@ -667,11 +801,13 @@
"filter": {
"age_rating": "التصنيف العمري",
"age_rating_none": "لا شيء",
"any": "أي",
"complete": "اكتمل",
"genre": "نوع",
"in_progress": "قيد التقدم",
"language": "اللغة",
"library": "المكتبة",
"oneshot": "قصة منفردة",
"publisher": "الناشر",
"read": "اقرأ",
"release_date": "تاريخ الاصدار",
@ -699,6 +835,8 @@
},
"library_navigation": {
"browse": "تصفّح",
"browse_books": "كتب",
"browse_series": "سلسلات",
"collections": "المجموعات",
"readlists": "قوائم القراءة",
"recommended": "موصى به"
@ -730,6 +868,7 @@
"empty_trash": "إفراغ سلة المهملات",
"mark_read": "تحديد كمقروء",
"mark_unread": "تحديد كغير مقروء",
"pin": "تثبيت",
"refresh_metadata": "تحديث البيانات الوصفية",
"scan_library_files": "فحص ملفات المكتبة",
"select_all": "تحديد الكل"
@ -745,6 +884,9 @@
"libraries": "المكتبات",
"logout": "تسجيل الخروج"
},
"no_libraries_pinned": {
"title": "لا مكتبات مثبتة"
},
"page_not_found": {
"go_back_to_home_page": "العودة إلى الصفحة الرئيسية",
"page_does_not_exist": "الصفحة التي تبحث عنها غير موجودة.",
@ -754,6 +896,12 @@
"less": "أقرأ أقل",
"more": "اقرأ أكثر"
},
"readlist_import": {
"row": {
"duplicate_book": "كتاب مكرر",
"error_choose_book": "اختيار كتاب"
}
},
"readlists_expansion_panel": {
"manage_readlist": "إدارة قائمة القراءة",
"title": "{name} قائمة القراءة"
@ -775,12 +923,21 @@
"button_empty_trash": "إفراغ سلة المهملات لكل المكتبات",
"button_scan_libraries": "مسح جميع المكتبات",
"button_shutdown": "إيقاف التشغيل",
"download_log": "تحميل ملف السجل",
"notification_tasks_cancelled": "لا يوجد مهام لإلغائها | تمّ إلغاء 1 مهمة | تمّ إلغاء {count} مهمة",
"section_title": "إدارة الخادم"
},
"tab_title": "خادم"
"tab_title": "خادم",
"updates": "تحديثات"
},
"server_settings": {
"dialog_regenerate_thumbnails": {
"btn_alternate": "نعم، جميع الكتب",
"btn_cancel": "لا",
"btn_confirm": "نعم، لكن فقط إن كانت اكبر"
},
"label_kobo_port": "باب مزامنة Kobo الخارجي",
"label_server_port": "باب الخادم",
"server_settings": "إعدادات الخادم"
},
"settings_user": {
@ -795,12 +952,15 @@
"sort": {
"books_count": "عدد الكتب",
"date_added": "تاريخ الإضافة",
"date_read": "تاريخ القراءة",
"date_updated": "تاريخ التحديث",
"file_name": "اسم الملف",
"file_size": "حجم الملف",
"folder_name": "اسم المجلد",
"name": "الاسم",
"number": "رقم",
"page_count": "عدد الصفحات",
"random": "عشوائي",
"release_date": "تاريخ الإصدار"
},
"theme": {
@ -818,16 +978,36 @@
"tooltip_too_big": "الملف كبير جدًا!",
"tooltip_user_uploaded": "تمّ الرفع بواسطة المستخدم"
},
"titles_more": {
"less": "عناوين أقل",
"more": "عناوين أكثر"
},
"ui_settings": {
"general": "عام",
"section_oauth2": "OAuth2",
"series_groups": {
"alpha": "ابجدي",
"japanese": "غوجون (ياباني)"
}
},
"updates": {
"available": "توجد تحديثات"
},
"user_roles": {
"ADMIN": "مدير",
"FILE_DOWNLOAD": "تحميل الملف",
"PAGE_STREAMING": "صفحات البث",
"KOBO_SYNC": "مزامنة Kobo",
"KOREADER_SYNC": "مزامنة KOReader",
"PAGE_STREAMING": "بث الصفحات",
"USER": "مستخدم"
},
"users": {
"api_keys": "مفاتيح الAPI",
"users": "المستخدمين"
},
"validation": {
"one_or_more": "يجب أن يكون 1 أو أكثر",
"tcp_port": "يجب أن يكون بين 1 و 65535",
"zero_or_more": "يجب أن يكون 0 أو أكثر"
},
"welcome": {

View file

@ -19,7 +19,15 @@
},
"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": {
"mark_all_read": "Отбележи всички като прочетени",
@ -27,6 +35,7 @@
"tab_title": "Обявления"
},
"authentication_activity": {
"api_key": "API ключ",
"datetime": "Дата Време",
"email": "Имейл",
"error": "Грешка",
@ -86,6 +95,7 @@
"beginning_of_book": "Вие сте в началото на книгата.",
"changing_reading_direction": "Смяна на посока на четене към",
"cycling_page_layout": "Циклиране на Подредба на Страница",
"cycling_page_margin": "Циклични Отстояния на Станици",
"cycling_scale": "Циклиране на Мащаб",
"cycling_side_padding": "Циклиране на Странична Подложка",
"download_current_page": "Свали текущата страница",
@ -128,6 +138,7 @@
"general": "Основни",
"gestures": "Жестове",
"page_layout": "Подреждане на страница",
"page_margin": "Отстояния на Страници",
"paged": "Опций на Странициран Четец",
"reading_mode": "Режим на четене",
"scale_type": "Тип мащабиране",
@ -161,6 +172,8 @@
},
"browse_book": {
"comment": "КОМЕНТАР",
"date_created": "СЪЗДАДЕНО",
"date_modified": "ПОСЛЕДНО ПРОМЕНЯНО",
"download_file": "Свали файл",
"file": "ФАЙЛ",
"format": "ФОРМАТ",
@ -170,6 +183,8 @@
"outdated_tooltip": "Файла за тази книга е променен, книгата трябва да бъде анализирана отново",
"read_book": "Чети книга",
"read_incognito": "Чети инкогнито",
"remove_from_collection": "Премахни книга от колекция",
"remove_from_readlist": "Премахни книга от списък за четене",
"size": "РАЗМЕР"
},
"browse_collection": {
@ -184,6 +199,7 @@
},
"browse_series": {
"earliest_year_from_release_dates": "Това е най-ранната година на издаване за всички книги в поредицата",
"remove_from_collection": "Премахни поредица от колекция",
"series_no_summary": "Тази поредица няма резюме, затова избрахме за Вас!",
"summary_from_book": "Резюме от книга {number}:"
},
@ -194,14 +210,18 @@
"common": {
"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}",
@ -210,8 +230,10 @@
"dismiss": "Отхвърли",
"download": "Свали",
"drag_drop": "теглене и пускане",
"duplicate": "Дубликирай",
"email": "Имейл",
"epub": "Epub",
"error": "Грешка",
"filename": "Име на файл",
"filter_no_matches": "Активният филтър няма съвпадения",
"genre": "Жанр",
@ -219,12 +241,16 @@
"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": "Страница",
@ -235,19 +261,23 @@
"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",
@ -271,6 +301,7 @@
"comicrack_preambule_html": "Можете да вмъкнете съществуващи списъци за четене на ComicRack във формат <code>.cbl</code>.<br>Komga ще се опита да съпостави предоставената поредица и номер на книга с поредици и книги във вашите библиотеки.",
"dialog_confirmation": {
"body": "{unmatched} / {total} книги са несравними",
"body2": "{duplicates} / {total} книги се дублират",
"create": "Създайте все пак",
"title": "Някои книги не съответстват"
},
@ -286,6 +317,14 @@
"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} серии",
@ -319,6 +358,12 @@
"filter": "Филтриране по номер на книгата, заглавие или дата на издаване",
"title": "Изберете книга"
},
"delete_apikey": {
"button_confirm": "Изтрий",
"confirm_delete": "Разбирам, изтрий API ключа \"{name}\"",
"dialog_title": "Изтрий API ключ",
"warning_html": "Всички приложения или скриптове ползващи този API ключ няма да могат да достигнат Komga API-то. Това действие не може да бъде отменено."
},
"delete_book": {
"button_confirm": "Изтрий",
"confirm_delete": "Да, изтрий книгата \"{name}\" и нейните файлове",
@ -417,6 +462,7 @@
"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 баркод",
@ -469,6 +515,11 @@
"tab_general": "Основни",
"tab_poster": "Плакат"
},
"edit_recommended": {
"button_confirm": "Запази промени",
"button_reset": "Възтанови в начални",
"dialog_title": "Редактирай предложеният изглед"
},
"edit_series": {
"button_cancel": "Отмени",
"button_confirm": "Запазване на промените",
@ -537,6 +588,10 @@
},
"title": "Име на Целевия Файл"
},
"force_kobo_sync": {
"dialog_title": "Принудително синхронизиране на Kobo",
"warning_html": "Това ще изтрие цялата история на синхронизация за този API ключ. Тоят Kobo ще синхронизира всичко на следващата синхронизациая."
},
"password_change": {
"button_cancel": "Отмени",
"button_confirm": "Промяна на паролата",
@ -604,8 +659,11 @@
"delete_to_save": "Изтрийте, за да запазите {size}",
"deleted_count": "Изтрит {count} пъти",
"empty_title": "Не са намерани дублирани страници",
"empty_title_known": "Няма известни дубликати",
"filter": {
"count": "Брой",
"date_added": "Дата на добавяне",
"date_modified": "Дата на промяна",
"delete_count": "Брой изтрити",
"delete_size": "Спестено място",
"match_count": "Брой съвпадения",
@ -617,7 +675,7 @@
"matches_n": "Няма съвпадения | 1 съвпадение | {count} съвпадения",
"new": "Нови",
"saved_size": "Спестено {size}",
"title": "Дублирани страници",
"title": "Дублирани Страници",
"unknown_size": "Неизвестен размер"
},
"duplicates": {
@ -633,7 +691,19 @@
},
"epubreader": {
"appearances": {
"day": "Ден"
"day": "Ден",
"night": "Нощ",
"sepia": "Сепия"
},
"column_count": {
"auto": "Авто",
"one": "Едно",
"two": "Две"
},
"reading_direction": {
"auto": "Автоматично",
"ltr": "От ляво на дясно",
"rtl": "От дясно на ляво"
}
},
"historical_event_type": {
@ -643,6 +713,11 @@
"DuplicatePageDeleted": "Дублираната страница е изтрита",
"SeriesFolderDeleted": "Папката на поредицата е изтрита"
},
"media_profile": {
"DIVINA": "DIVINA",
"EPUB": "EPUB",
"PDF": "PDF"
},
"media_status": {
"ERROR": "Грешка",
"OUTDATED": "Остарял",
@ -661,6 +736,14 @@
"VERTICAL": "Вертикално",
"WEBTOON": "Уебтун"
},
"scan_interval": {
"DAILY": "Дневно",
"DISABLED": "Спряно",
"EVERY_12H": "На всеки 12 часа",
"EVERY_6H": "На всеки 6 часа",
"HOURLY": "На час",
"WEEKLY": "Седмично"
},
"series_cover": {
"FIRST": "Първа",
"FIRST_UNREAD_OR_FIRST": "Първа непрочетена иначе първа",
@ -672,11 +755,21 @@
"ENDED": "Приключила",
"HIATUS": "Хиатус",
"ONGOING": "Продължава"
},
"thumbnail_size": {
"DEFAULT": "По подразбиране (300px)",
"LARGE": "Голямо (900px)",
"MEDIUM": "Средно (600px)",
"XLARGE": "Много Голямо (1200px)"
}
},
"epubreader": {
"current_chapter": "Текуща глава",
"page_of": "Станица {page} от {count}",
"publisher_font": "Издателство",
"settings": {
"column_count": "Брой колони",
"font_family": "Шрифт",
"layout": "Оформление",
"layout_paginated": "Страницирано",
"layout_scroll": "Позициониране",
@ -698,7 +791,7 @@
"next": "Напред",
"previous": "Назад",
"reader_navigation": "Навигация на четец",
"scroll": "Промени оформление към позициониране",
"scroll": "Превключи на непрекъснато превъртане",
"settings": "Настройки",
"show_hide_toc": "Покажи/скрий съдържание"
}
@ -731,17 +824,27 @@
"ERR_1029": "ComicRack CBL не съдържа никакъв елемент Book",
"ERR_1030": "ComicRack CBL няма елемент Name",
"ERR_1031": "ComicRack CBL в Book липсва серия или номер",
"ERR_1032": "EPUB файл е с грешен тип медия"
"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": "библиотека",
"oneshot": "Единично",
"media_profile": "Профил на медия",
"media_status": "Статус на медиа",
"oneshot": "Самостоятелно издание",
"publisher": "издателство",
"read": "Прочетени",
"release_date": "дата на издаване",
@ -770,6 +873,8 @@
},
"library_navigation": {
"browse": "Преглед",
"browse_books": "Книги",
"browse_series": "Поредици",
"collections": "Колекции",
"readlists": "Списъци за Четене",
"recommended": "Препоръчани"
@ -781,7 +886,7 @@
},
"media_analysis": {
"comment": "Коментар",
"media_analysis": "Медиен анализ",
"media_analysis": "Медиен Анализ",
"media_type": "Тип на Медията",
"name": "Име",
"size": "Размер",
@ -802,10 +907,12 @@
"empty_trash": "Изпразване на кошчето",
"mark_read": "Отбележи като прочетено",
"mark_unread": "Отбележи като непрочетено",
"pin": "Закачи",
"refresh_metadata": "Опресняване на метаданните",
"scan_library_files": "Сканирайте библиотечните файлове",
"scan_library_files_deep": "Сканирай библиотека за файлове (дълбоко)",
"select_all": "Изберете всички"
"select_all": "Изберете всички",
"unpin": "Разкачи"
},
"metrics": {
"library_books": "Книги на библиотека",
@ -816,11 +923,18 @@
"tasks_total_time": "Общо време на задачите",
"title": "Показатели"
},
"missing_posters": {
"title": "Липсващ Постер"
},
"navigation": {
"home": "Начало",
"libraries": "Библиотеки",
"logout": "Изход"
},
"no_libraries_pinned": {
"subtitle": "Може да закачиш библиотеки от менюто с 3 точки",
"title": "Няма закачени библиотеки"
},
"page_not_found": {
"go_back_to_home_page": "Връщане към началната страница",
"page_does_not_exist": "Страницата, която търсите, не съществува.",
@ -858,10 +972,12 @@
"button_scan_libraries": "Сканиране на всички библиотеки",
"button_scan_libraries_deep": "Сканирай всички библиотеки (дълбоко)",
"button_shutdown": "Изключване",
"download_log": "Изтегли лог файл",
"notification_tasks_cancelled": "Няма задачи за отмяна | Една отменена задача | {count} отменени задачи",
"section_title": "Управление на сървъра"
},
"tab_title": "Сървър"
"tab_title": "Сървър",
"updates": "Обновления"
},
"server_settings": {
"config_precedence": "Има предимство пред конфигурационния файл",
@ -872,8 +988,12 @@
"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 Sync заявки към Kobo Store",
"label_rememberme_duration": "Запомни ме за период (в дни)",
"label_server_context_path": "Базов URL",
"label_server_port": "Прот на сървъра",
@ -894,13 +1014,17 @@
"sort": {
"books_count": "Брой книги",
"date_added": "Дата на добавяне",
"date_read": "Дата на четене",
"date_updated": "Дата на актуализация",
"file_name": "Име на файл",
"file_size": "Размер на файла",
"folder_name": "Име на папка",
"name": "Име",
"number": "Номер",
"release_date": "Дата на издаване"
"page_count": "Брой страници",
"random": "Случайно",
"release_date": "Дата на издаване",
"series": "Поредица"
},
"theme": {
"dark": "Тъмна",
@ -922,13 +1046,34 @@
"less": "По-малко заглавия",
"more": "Още заглавия"
},
"ui_settings": {
"general": "Основни",
"label_oauth2_auto_login": "Автоматичнен OAuth2 login",
"label_oauth2_hide_login": "Скрий логин полетата ако OAuth2 е включено",
"label_poster_blur_unread": "Замажи постери за непречетени книги и поредици",
"label_poster_stretch": "Разтегли постези за да изпълнят картата",
"label_series_groups": "Групиране на поредици",
"section_oauth2": "OAuth2",
"series_groups": {
"alpha": "Азбучно",
"japanese": "Gojūon (Японски)"
},
"tooltip_oauth2_auto_login": "Изисква единен OAuth2 източник, и 'скрити логин полета' включени"
},
"updates": {
"available": "Има налични обновления",
"latest_installed": "Последната версия на Komga е инсталирана"
},
"user_roles": {
"ADMIN": "Администратор",
"FILE_DOWNLOAD": "Изтегляне на файлове",
"KOBO_SYNC": "Kobo Sync",
"KOREADER_SYNC": "KOReader Sync",
"PAGE_STREAMING": "Стриймване на страници",
"USER": "Потребител"
},
"users": {
"api_keys": "API ключове",
"authentication_activity": "Дейност по удостоверяване",
"users": "Потребители"
},

View file

@ -27,7 +27,7 @@
},
"change_password": "Passwort ändern",
"details": "Details",
"my_account": "Mein Account"
"my_account": "Mein Konto"
},
"announcements": {
"mark_all_read": "Alle als gelesen markieren",
@ -52,7 +52,7 @@
"letterer": "Setzer",
"penciller": "Zeichner",
"translator": "Übersetzer",
"writer": "Schriftsteller"
"writer": "Autoren"
},
"book_card": {
"error": "Fehler",
@ -104,9 +104,9 @@
"move_next": "Klicken oder drücken Sie „Weiter“, um zum nächsten Buch zu gelangen.",
"move_next_exit": "Klicken oder drücken Sie „Weiter“ erneut, um den Lesemodus zu beenden.",
"move_previous": "Klicken oder drücken Sie erneut auf „Vorherige Seite“, um zum letzten Buch zu wechseln.",
"notification_poster_set_book": "Die aktuelle Seite ist nun als Bücherplakat gesetzt.",
"notification_poster_set_readlist": "Die aktuelle Seite ist als Leselistenposter gesetzt.",
"notification_poster_set_series": "Die aktuelle Seite ist jetzt als Serienplakat gesetzt.",
"notification_poster_set_book": "Die aktuelle Seite ist jetzt als Titelbild definiert.",
"notification_poster_set_readlist": "Die aktuelle Seite wurde als Titelbild für die Lesteliste festgelegt.",
"notification_poster_set_series": "Die aktuelle Seite wurde als Titelbild der Serie festgelegt.",
"paged_reader_layout": {
"double": "Doppelseite",
"double_no_cover": "Doppelseitig ohne Titelbild",
@ -122,9 +122,9 @@
"width": "An Breite ausrichten",
"width_shrink_only": "An Breite ausrichten (nur verkleinern)"
},
"set_current_page_as_book_poster": "Seite als Plakat für das Buch gesetzt",
"set_current_page_as_readlist_poster": "Setze die aktuelle Seite als Plakat für die Leseliste",
"set_current_page_as_series_poster": "Seite zu Serienposter",
"set_current_page_as_book_poster": "Diese Seite als Titelbild für das Buch festlegen",
"set_current_page_as_readlist_poster": "Diese Seite als Titelbild für die Leseliste festlegen",
"set_current_page_as_series_poster": "Diese Seite als Titelbild für die Serie festlegen",
"settings": {
"always_fullscreen": "Dauerhaftes Vollbild",
"animate_page_transitions": "Fließender Seitenübergangseffekt",
@ -202,7 +202,7 @@
"earliest_year_from_release_dates": "Dies ist das früheste Erscheinungsjahr von allen Büchern in der Serie",
"remove_from_collection": "Entferne Serie aus der Sammlung",
"series_no_summary": "Diese Serie hat keine Kurzbeschreibung, es wurde eine aus der Serie per Zufall ausgewählt!",
"summary_from_book": "Inhaltsangabe des Buches {number}:"
"summary_from_book": "Inhaltsangabe von Buch {number}:"
},
"collections_expansion_panel": {
"manage_collection": "Sammlungverwaltung",
@ -247,7 +247,7 @@
"locale_name": "Deutsch",
"locale_rtl": "false",
"lock_all": "Alle sperren",
"media": "Media",
"media": "Medien",
"more": "Mehr",
"n_selected": "{count} markiert",
"nothing_to_show": "Nichts anzuzeigen",
@ -351,7 +351,7 @@
"field_password": "Passwort"
},
"analyze_library": {
"body": "Analysiert alle Mediendateien in der Bibliothek. Bei der Analyse werden Informationen über die Medien erfasst. Je nach Größe Ihrer Bibliothek kann dies sehr lange dauern.",
"body": "Analysiert alle Mediendateien in der Bibliothek. Bei der Analyse werden Informationen über die Mediendatien erfasst. Je nach Größe Ihrer Bibliothek kann dies sehr lange dauern.",
"button_confirm": "Analysieren",
"title": "Bibliothek analysieren"
},
@ -371,8 +371,8 @@
"confirm_delete_multiple": "Ja, lösche {count} Bücher und die dazugehörigen Dateien",
"dialog_title": "Buch löschen",
"dialog_title_multiple": "Bücher löschen",
"warning_html": "Das Buch <b>{name}</b> wird vom Server inklusive der gespeicherten Daten auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?",
"warning_multiple_html": "{count} Bücher werden vom Server inklusive der gespeicherten Daten auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?"
"warning_html": "Das Buch <b>{name}</b> wird vom Server inklusive der gespeicherten Dateien auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?",
"warning_multiple_html": "{count} Bücher werden vom Server inklusive der gespeicherten Dateien auf der Festplatte entfernt. Dies <b>kann nicht</b> rückgängig gemacht werden. Forfahren?"
},
"delete_collection": {
"button_confirm": "Löschen",
@ -380,14 +380,14 @@
"confirm_delete_multiple": "Ja, {count} Sammlung(en) löschen",
"dialog_title": "Sammlung löschen",
"dialog_title_multiple": "Sammlungen löschen",
"warning_html": "Die Sammlung <b>{name}</b> wird vom Server entfernt. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
"warning_html": "Die Sammlung <b>{name}</b> wird vom Server entfernt. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
"warning_multiple_html": "{count} Sammlungen werden von diesem Server entfernt. Ihre Mediendateien sind davon nicht betroffen. Dies kann <b>nicht</b> rückgängig gemacht werden. Fortsetzen?"
},
"delete_library": {
"button_confirm": "Löschen",
"confirm_delete": "Ja, die Bibliothek „{name}“ löschen",
"title": "Bibliothek löschen",
"warning_html": "Die Bibliothek <b>{name}</b> wird vom Server gelöscht. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
"warning_html": "Die Bibliothek <b>{name}</b> wird vom Server gelöscht. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
},
"delete_readlist": {
"button_confirm": "Löschen",
@ -395,7 +395,7 @@
"confirm_delete_multiple": "Ja, {count} Leselisten löschen",
"dialog_title": "Leseliste löschen",
"dialog_title_multiple": "Leselisten löschen",
"warning_html": "Die Leseliste <b>{name}</b> wird vom Server entfernt. Die physikalischen Dateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
"warning_html": "Die Leseliste <b>{name}</b> wird vom Server entfernt. Die Mediendateien bleiben unverändert. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?",
"warning_multiple_html": "{count} Leselisten werden von diesem Server entfernt. Ihre Mediendateien sind davon nicht betroffen. Dies <b>kann nicht</b> rückgängig gemacht werden. Fortsetzen?"
},
"delete_series": {
@ -413,7 +413,7 @@
"warning_html": "Der Benutzer <b>{name}</b> wird gelöscht. Dies kann <b>NICHT</b> rückgängig gemacht werden. Fortfahren?"
},
"edit_books": {
"add_author_role_error_duplicate": "Author existiert bereits",
"add_author_role_error_duplicate": "Autor existiert bereits",
"authors_notice_multiple_edit": "Sie verändern mehrere Bücher. Dies wird die existierenden Einträge der Autoren jedes einzelnen Buches durch den neuen Eintrag ersetzen.",
"button_cancel": "Abbrechen",
"button_confirm": "Änderungen speichern",
@ -440,7 +440,7 @@
"tab_authors": "Autoren",
"tab_general": "Allgemein",
"tab_links": "Links",
"tab_poster": "Poster",
"tab_poster": "Titelbild",
"tab_tags": "Stichwörter",
"tags_notice_multiple_edit": "Sie verändern die Stichwörter von mehreren Büchern. Dies wird die existierenden Einträge der Stichwörter jedes einzelnen Buches durch den neuen Eintrag ersetzen."
},
@ -451,7 +451,7 @@
"field_manual_ordering": "Manuelle Sortierung",
"label_ordering": "Sammlungen werden standardmäßig nach Namen sortiert. Sie können die manuelle Sortierung aktivieren und eine eigene Sortierfolge festlegen.",
"tab_general": "Allgemein",
"tab_poster": "Poster"
"tab_poster": "Titelbild"
},
"edit_library": {
"button_browse": "Durchsuchen",
@ -463,7 +463,7 @@
"dialot_title_edit": "Bibliothek bearbeiten",
"field_analysis_analyze_dimensions": "Analysiere Seitenformat",
"field_analysis_hash_files": "Erzeuge einen Hash für Dateien",
"field_analysis_hash_koreader": "Compute Hash für KO Reader Dateien",
"field_analysis_hash_koreader": "Erzeuge einen Hash für KO Reader Dateien",
"field_analysis_hash_pages": "Erzeuge einen Hash für Seiten",
"field_convert_to_cbz": "Automatisch in CBZ konvertieren",
"field_import_barcode_isbn": "ISBN Strichcode",
@ -514,7 +514,7 @@
"field_summary": "Zusammenfassung",
"label_ordering": "Standardmäßig werden die Bücher in einer Leseliste manuell sortiert. Sie können die manuelle Sortierung deaktivieren, um die Bücher nach Erscheinungsdatum zu sortieren.",
"tab_general": "Allgemein",
"tab_poster": "Poster"
"tab_poster": "Titelbild"
},
"edit_recommended": {
"button_confirm": "Änderungen speichern",
@ -543,7 +543,7 @@
"field_total_book_count_error": "Anzahl der Bücher einer Serie muß größer eins sein",
"mixed": "Vermischtes",
"tab_general": "Allgemein",
"tab_poster": "Poster",
"tab_poster": "Titelbild",
"tab_sharing": "Teilen",
"tab_tags": "Stichwörter",
"tab_titles": "Alternative Titel",
@ -591,7 +591,7 @@
},
"force_kobo_sync": {
"dialog_title": "Erzwinge Kobo Sync",
"warning_html": "Dies löscht die komplette Sync Historie für diesen API Schlüssel. Dein Kobo wird einen vollständigen Sync beim nächsten Mal durchführen."
"warning_html": "Dies löscht den kompletten Synchronisierungverlauf für diesen API Schlüssel. Dein Kobo beim nächsten Mal eine vollständige Synchronisierung durchführen."
},
"password_change": {
"button_cancel": "Abbrechen",
@ -818,7 +818,7 @@
"ERR_1022": "Ein neu importiertes Buch konnte nicht gescannt werden",
"ERR_1023": "Buch ist in der Leseliste schon vorhanden",
"ERR_1024": "OAuth2 Anmeldefehler: Kein E-Mail Attribut",
"ERR_1025": "OAuth2 Anmeldefehler: Keinen lokalen Nutzer mit eingegebener E-Mail gefunden",
"ERR_1025": "OAuth2 Anmeldefehler: Keinen lokalen Nutzer mit der angegebenen E-Mail gefunden",
"ERR_1026": "OpenID Connect Anmeldefehler: E-Mail nicht verifiziert",
"ERR_1027": "OpenID Connect-Anmeldefehler: Fehlendes email_verified Attribut",
"ERR_1028": "OpenID Connect-Anmeldefehler: kein E-Mail Attribut",
@ -866,11 +866,11 @@
"series": "Serie",
"type": "Type"
},
"title": "Historie"
"title": "Verlauf"
},
"home": {
"theme": "Design",
"translation": "Übersetzung"
"translation": "Sprache"
},
"library_navigation": {
"browse": "Stöbern",
@ -878,7 +878,7 @@
"browse_series": "Serien",
"collections": "Sammlungen",
"readlists": "Leseliste",
"recommended": "Empfohlen"
"recommended": "Empfehlungen"
},
"login": {
"create_user_account": "Benutzerkonto erstellen",
@ -887,7 +887,7 @@
},
"media_analysis": {
"comment": "Kommentar",
"media_analysis": "Medien Analyse",
"media_analysis": "Medienanalyse",
"media_type": "Medientyp",
"name": "Name",
"size": "Größe",
@ -896,7 +896,7 @@
},
"menu": {
"add_to_collection": "Zu Sammlung hinzufügen",
"add_to_readlist": "Füge zur Leseliste hinzu",
"add_to_readlist": "Zur Leseliste hinzufügen",
"analyze": "Analysieren",
"bulk_edit_metadata": "Massenverarbeitung Metadaten",
"delete": "Löschen",
@ -909,7 +909,7 @@
"mark_read": "Als gelesen markieren",
"mark_unread": "Als ungelesen markieren",
"pin": "Anpinnen",
"refresh_metadata": "Erneuere Metadaten",
"refresh_metadata": "Metadaten aktualisieren",
"scan_library_files": "Überprüfe (Scan) Bibliotheksdateien",
"scan_library_files_deep": "(Tiefen) Scan der Bibliotheksdateien",
"select_all": "Alle auswählen",
@ -922,10 +922,10 @@
"library_sidecars": "Extras pro Bibliothek",
"tasks_executed": "Aufgaben ausgeführt",
"tasks_total_time": "Benötigte Gesamtzeit für die Aufgaben",
"title": "Metriken"
"title": "Statistik"
},
"missing_posters": {
"title": "Fehlende Poster"
"title": "Fehlende Titelbilder"
},
"navigation": {
"home": "Übersicht",
@ -990,7 +990,7 @@
"title": "Vorschaubilder neu generieren"
},
"hint_kobo_port": "Nur zu setzen wenn es Sync Probleme mit Covers und Downloads gibt",
"label_delete_empty_collections": "Lösche leere Kollectionen nach der Prüfung (Scan)",
"label_delete_empty_collections": "Lösche leere Kollektionen nach der Prüfung (Scan)",
"label_delete_empty_readlists": "Lösche leere Leselisten nach der Überprüfung (Scan)",
"label_kepubify_path": "Dateipfad zu kepubify",
"label_kobo_port": "Kobo Sync externer Port",
@ -1009,7 +1009,7 @@
"edit_user": "Benutzerdaten bearbeiten",
"latest_activity": "Letzte Aktivität: {date}",
"no_recent_activity": "Keine letzten Aktivitäten",
"role_administrator": "Systemverwalter",
"role_administrator": "Administrator",
"role_user": "Benutzer"
},
"sort": {
@ -1023,7 +1023,7 @@
"name": "Nach Name sortiert",
"number": "Nummer",
"page_count": "Anzahl Seiten",
"random": "Zufallsortierung",
"random": "Zufällige Sortierung",
"release_date": "Veröffentlichungsdatum",
"series": "Serie"
},
@ -1049,10 +1049,10 @@
},
"ui_settings": {
"general": "Allgemein",
"label_oauth2_auto_login": "Automatischer OAuth2 Login",
"label_oauth2_hide_login": "Verstecke die Login Felder wenn OAuth2 aktiviert ist",
"label_poster_blur_unread": "Vertrübe Poster für ungelesene Bücher und Serien",
"label_poster_stretch": "Passe die Poster den Kacheln an",
"label_oauth2_auto_login": "Automatische Anmeldung über OAuth2",
"label_oauth2_hide_login": "Anmeldefelder ausblenden, wenn OAuth2 aktiviert ist",
"label_poster_blur_unread": "Unscharfe Titelbilder bei ungelesene Bücher und Serien",
"label_poster_stretch": "Titelbilder an die Kachelgröße anpassen",
"label_series_groups": "Seriengruppierung",
"section_oauth2": "OAuth2",
"series_groups": {
@ -1067,7 +1067,7 @@
},
"user_roles": {
"ADMIN": "Systemverwalter",
"FILE_DOWNLOAD": "Datei-Herunterladen",
"FILE_DOWNLOAD": "Dateien herunterladen",
"KOBO_SYNC": "Kobo Syncronisation",
"KOREADER_SYNC": "KOReader Synchronisation",
"PAGE_STREAMING": "Online lesen",

View file

@ -19,7 +19,15 @@
},
"account_settings": {
"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": {
"mark_all_read": "Marcar todo como lido",
@ -27,6 +35,7 @@
"tab_title": "Avisos"
},
"authentication_activity": {
"api_key": "Clave API",
"datetime": "Data e Hora",
"email": "Correo electrónico",
"error": "Erro",
@ -58,9 +67,196 @@
"button_scan": "Escanear",
"button_select_series": "Escolle a serie",
"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",
"width": "Axusta ó ancho",
"width_shrink_only": "Axusta ó ancho (só encoller)"
},
"set_current_page_as_book_poster": "Escolle a páxina como cuberta do libro",
"set_current_page_as_readlist_poster": "Escolle a páxina como cuberta da lista de lectura",
"set_current_page_as_series_poster": "Escolle a páxina como cuberta da serie",
"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"
},
"display": "Pantalla",
"general": "Xeral",
"gestures": "Xestos",
"page_layout": "Disposición de páxina",
"page_margin": "Marxe de páxina",
"paged": "Opcións de paxinado do lector",
"reading_mode": "Modo de lectura",
"scale_type": "Tipo de escala",
"side_padding": "Espazo lateral",
"side_padding_none": "Ningún",
"webtoon": "Opcións do lector de Webtoon"
},
"shortcuts": {
"close": "Pechar",
"cycle_page_layout": "Cambiar a disposición da páxina",
"cycle_page_margin": "Cambia a marxe da páxina",
"cycle_scale": "Cambia a escala",
"cycle_side_padding": "Cambia o espaciado lateral",
"first_page": "Primeira páxina",
"fullscreen": "Entrar/Saír da pantalla completa",
"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",
"reader_navigation": "Navegación do lector",
"right_to_left": "De dereita a esquerda",
"settings": "Axustes",
"show_hide_help": "Mostra/agocha a axuda",
"show_hide_settings": "Mostra/agocha o menú de axuda",
"show_hide_thumbnails": "Mostra/agocha o explorador de miniaturas",
"show_hide_toolbars": "Mostra/agocha as barras de ferramentas",
"vertical": "Vertical",
"webtoon": "Webtoon"
},
"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",
"navigation_within_readlist": "Navegación na lista de lectura:{name}",
"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": {
"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",
"cbx": "Arquivos de Cómics",
"choose_image": "Escoller unha imaxe",
"close": "Pechar",
"collections": "Coleccións",
"copied": "Copiado!",
"create": "Crear",
"delete": "Borrar",
"dimension": "anch.: {width}, alt.: {height}",
"discard": "Descartar",
"disk_space": "Espazo en disco",
"dismiss": "Desbota",
"download": "Baixar",
"drag_drop": "Arrastra e solta",
"duplicate": "Duplicar",
"email": "Correo electrónico",
"epub": "EPUB",
"error": "Erro",
"filename": "Nome de ficheiro",
"filter_no_matches": "O filtro activo non atopa semellanzas",
"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",
"locale_rtl": "false",
"lock_all": "Bloquea todo",
"media": "Medios",
"more": "Máis",
"n_selected": "{count} seleccionado(s)",
"nothing_to_show": "Nada que amosar",
"ok": "Ok",
"oneshot": "Volume único",
"outdated": "Desactualizado",
"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"
}
}

View file

@ -46,7 +46,7 @@
},
"author_roles": {
"colorist": "koloristi",
"cover": "omot",
"cover": "naslovnica",
"editor": "urednici",
"inker": "bojitelj",
"letterer": "tipografi",
@ -109,7 +109,7 @@
"notification_poster_set_series": "Trenutačna stranica je sada postavljena kao poster serije.",
"paged_reader_layout": {
"double": "Dvije stranice",
"double_no_cover": "Dvije stranice (bez omota)",
"double_no_cover": "Dvije stranice (bez naslovnice)",
"single": "Jedna stranica"
},
"reader_settings": "Postavke čitača",
@ -253,7 +253,7 @@
"nothing_to_show": "Nema ničega za pokazati",
"ok": "U redu",
"oneshot": "Izdanje bez nastavka",
"outdated": "Neaktualno",
"outdated": "Zastarjelo",
"page": "Stranica",
"page_number": "Broj stranice",
"pages": "stranice",
@ -484,7 +484,7 @@
"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_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_title": "Osnovna mapa biblioteke",
"label_analysis": "Analiza",
@ -495,9 +495,9 @@
"label_import_local": "Uvezi lokalne medije",
"label_import_mylar": "Uvezi metapodatke generirane pomoću Mylar-a",
"label_scan_directory_exclusions": "Isključivanja mapa",
"label_scan_types": "Traži ove vrste datoteka",
"label_scanner": "Tražilica",
"label_series_cover": "Omot serije",
"label_scan_types": "Pretraži ove vrste datoteka",
"label_scanner": "Pretraživanje",
"label_series_cover": "Naslovnica serije",
"tab_general": "Općenito",
"tab_metadata": "Metapodaci",
"tab_options": "Opcije",
@ -526,8 +526,8 @@
"button_confirm": "Spremi promjene",
"dialog_title_multiple": "Uredi {count} seriju | Uredi {count} serije",
"dialog_title_single": "Uredi {series}",
"field_age_rating": "Dobna kategorija",
"field_age_rating_error": "Dobna kategorija mora biti 0 ili više",
"field_age_rating": "Dobna klasifikacija",
"field_age_rating_error": "Dobna klasifikacija mora biti 0 ili više",
"field_genres": "Žanrovi",
"field_labels": "Etikete",
"field_language": "Jezik",
@ -721,7 +721,7 @@
},
"media_status": {
"ERROR": "Greška",
"OUTDATED": "Neaktualno",
"OUTDATED": "Zastarjelo",
"READY": "Spremno",
"UNKNOWN": "Nepoznato",
"UNSUPPORTED": "Nepodržano"
@ -835,7 +835,7 @@
"ERR_1039": "Greška prilikom dohvaćanja pozicija EPUB-a"
},
"filter": {
"age_rating": "dobna kategorija",
"age_rating": "dobna klasifikacija",
"age_rating_none": "Bez",
"any": "Bilo koji",
"complete": "Dovršeno",
@ -973,9 +973,9 @@
"button_scan_libraries": "Pretraži sve biblioteke",
"button_scan_libraries_deep": "Pretraži sve biblioteke (duboko)",
"button_shutdown": "Isključi",
"download_log": "Preuzmi datoteku zapisa",
"download_log": "Preuzmi log-datoteku",
"notification_tasks_cancelled": "Nema zadataka za prekidanje | Jedan zadatak prekinut | {count} zadatka prekinuta",
"section_title": "Upravljanje serverom"
"section_title": "Upravljanje serverima"
},
"tab_title": "Server",
"updates": "Aktualiziranja"
@ -989,7 +989,7 @@
"btn_confirm": "Da, ali samo ako su veće",
"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_readlists": "Izbriši prazne liste čitanja nakon pretraživanja",
"label_kepubify_path": "Staza do kepubify",

View file

@ -396,15 +396,15 @@
"dialog_title": "읽기 목록 삭제",
"dialog_title_multiple": "읽기 목록 삭제",
"warning_html": "읽기 목록 <b>{name}</b> 이(가) 이 서버에서 제거됩니다. 미디어 파일은 영향을 받지 않습니다. <b>이 일은 되돌릴 수 없습니다.</b> 계속하시겠습니까?",
"warning_multiple_html": "{count}개의 읽기 목록이 서버에서 제거됩니다. 미디어 파일은 영향을 받지 않습니다. <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> 계속하시겠습니까?"
"warning_html": "시리즈 <b>{name}</b> 이(가) 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 작업은 되돌릴 수 없습니다.</b> 계속하시겠습니까?",
"warning_multiple_html": "{count}개의 시리즈가 저장된 미디어 파일과 함께 이 서버에서 제거됩니다. <b>이 작업은 되돌릴 수 없습니다.</b> 계속하시겠습니까?"
},
"delete_user": {
"button_confirm": "삭제",

View file

@ -212,7 +212,7 @@
"age": "Idade",
"all_libraries": "Todas as bibliotecas",
"all_of": "Todos",
"any_of": "Qualquer",
"any_of": "Qualquer um",
"book": "Livro",
"books": "Livros",
"books_n": "Nenhum livro | 1 livro | {count} livros",
@ -228,7 +228,7 @@
"dimension": "l: {width}, a:{height}",
"discard": "Descartar",
"disk_space": "Espaço em disco",
"dismiss": "Ignorar",
"dismiss": "Dispensar",
"download": "Baixar",
"drag_drop": "Arrastar e soltar",
"duplicate": "Duplicado",
@ -319,7 +319,12 @@
},
"dialog": {
"add_api_key": {
"button_confirm": "Gerar"
"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": {
"button_create": "Criar",
@ -354,6 +359,12 @@
"filter": "Filtrar por número, título ou data de lançamento",
"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": {
"button_confirm": "Excluir",
"confirm_delete": "Sim, exclua o livro \"{name}\" e seus arquivos",
@ -452,6 +463,7 @@
"dialot_title_edit": "Editar Biblioteca",
"field_analysis_analyze_dimensions": "Analisar as dimensões das paginas",
"field_analysis_hash_files": "Computar hash para arquivos",
"field_analysis_hash_koreader": "Computar hash para arquivos para o KOReader",
"field_analysis_hash_pages": "Computar hash para páginas",
"field_convert_to_cbz": "Converter automaticamente para CBZ",
"field_import_barcode_isbn": "Código de barra ISBN",
@ -465,6 +477,7 @@
"field_import_local_artwork": "Mídia local",
"field_import_mylar_series": "Metadados de séries",
"field_name": "Nome",
"field_oneshotsdirectory": "Diretório de One-Shots",
"field_repair_extensions": "Reparar extensões de arquivo incorretas automaticamente",
"field_root_folder": "Pasta raíz",
"field_scan_interval": "Intervalo de scan",
@ -503,6 +516,11 @@
"tab_general": "Geral",
"tab_poster": "Pôster"
},
"edit_recommended": {
"button_confirm": "Salvar mudanças",
"button_reset": "Redefinir para o padrão",
"dialog_title": "Editar visualização recomendada"
},
"edit_series": {
"button_cancel": "Cancelar",
"button_confirm": "Salvar mudanças",
@ -571,6 +589,10 @@
},
"title": "Nome do Arquivo de Destino"
},
"force_kobo_sync": {
"dialog_title": "Forçar sincronização com Kobo",
"warning_html": "Isso excluirá todo o histórico de sincronização para esta chave de API. Seu Kobo sincronizará tudo na próxima sincronização."
},
"password_change": {
"button_cancel": "Cancelar",
"button_confirm": "Mudar senha",
@ -587,6 +609,7 @@
},
"series_picker": {
"label_search_series": "Buscar Séries",
"no_results": "Nenhuma serie encontrada",
"title": "Selecionar Série"
},
"server_stop": {
@ -625,12 +648,41 @@
}
},
"duplicate_pages": {
"action_auto_delete_remaining": "Exclusão automática restantes {count}",
"action_delete_auto": "Exclusão automática",
"action_delete_manual": "Exclusão manual",
"action_delete_matches": "Excluir correspondências",
"action_ignore": "Ignorar",
"action_ignore_remaining": "{count} ignorados restantes",
"action_manual_delete_remaining": "Exclusão manual restantes {count}",
"confirm_auto_delete_remaining": "Todos os hashes de página restantes nesta página {count} serão marcados para exclusão automática.",
"confirm_manual_delete_remaining": "Todos os hashes de página restantes nesta página {count} serão marcados para exclusão manual.",
"delete_to_save": "Exclua para economizar {size}",
"deleted_count": "Deletada {count} vezes",
"empty_title": "Nenhuma página duplicada encontrada",
"empty_title_known": "Nenhuma duplicata encontrada",
"filter": {
"size": "Tamanho"
}
"count": "Contagem",
"date_added": "Data de adição",
"date_modified": "Data de modificação",
"delete_count": "Contagem de exclusão",
"delete_size": "Espaço economizado",
"match_count": "Contagem de correspondência",
"size": "Tamanho",
"total_size": "Tamanho total"
},
"info": "Excluir páginas duplicadas modificará seus arquivos. Faça backup de seus arquivos e use a exclusão manual antes de usar a exclusão automática.",
"known": "Conhecidas",
"matches_n": "Nenhuma correspondência | 1 correspondência | {count} correspondências",
"new": "Novo",
"saved_size": "Salvou {size}",
"title": "Duplicar páginas",
"unknown_size": "Tamanho desconhecido"
},
"duplicates": {
"file_hash": "Hash do arquivo",
"size": "Tamanho",
"title": "Duplicar arquivos",
"url": "URL"
},
"enums": {
@ -638,6 +690,35 @@
"HARDLINK": "Hardlink/Copiar arquivos",
"MOVE": "Mover Arquivos"
},
"epubreader": {
"appearances": {
"day": "Dia",
"night": "Noite",
"sepia": "Sépia"
},
"column_count": {
"auto": "Auto",
"one": "Uma",
"two": "Duas"
},
"reading_direction": {
"auto": "Automático",
"ltr": "Da esquerda para a direita",
"rtl": "Da direita para a esquerda"
}
},
"historical_event_type": {
"BookConverted": "Livro convertido",
"BookFileDeleted": "Arquivo de livro excluído",
"BookImported": "Livro importado",
"DuplicatePageDeleted": "Página duplicada excluída",
"SeriesFolderDeleted": "Pasta da série excluída"
},
"media_profile": {
"DIVINA": "DIVINA",
"EPUB": "EPUB",
"PDF": "PDF"
},
"media_status": {
"ERROR": "Erro",
"OUTDATED": "Desatualizado",
@ -645,12 +726,25 @@
"UNKNOWN": "Desconhecido",
"UNSUPPORTED": "Não Suportado"
},
"page_hash_action": {
"DELETE_AUTO": "Exclusão automática",
"DELETE_MANUAL": "Exclusão manual",
"IGNORE": "Ignorar"
},
"reading_direction": {
"LEFT_TO_RIGHT": "Esquerda para direita",
"RIGHT_TO_LEFT": "Direita para esquerda",
"VERTICAL": "Vertical",
"WEBTOON": "Webtoon"
},
"scan_interval": {
"DAILY": "Diariamente",
"DISABLED": "Desativado",
"EVERY_12H": "A cada 12 horas",
"EVERY_6H": "A cada 6 horas",
"HOURLY": "A cada 1 hora",
"WEEKLY": "Semanalmente"
},
"series_cover": {
"FIRST": "Primeiro",
"FIRST_UNREAD_OR_FIRST": "Primeiro não lido ou primeiro",
@ -662,6 +756,45 @@
"ENDED": "Finalizado",
"HIATUS": "Interrompido",
"ONGOING": "Em andamento"
},
"thumbnail_size": {
"DEFAULT": "Padrão (300px)",
"LARGE": "Grande (900px)",
"MEDIUM": "Médio (600px)",
"XLARGE": "Extra Grande (1200px)"
}
},
"epubreader": {
"current_chapter": "Capítulo atual",
"page_of": "Página {page} de {count}",
"publisher_font": "Editora",
"settings": {
"column_count": "Colunas",
"font_family": "Fonte",
"layout": "Layout",
"layout_paginated": "Paginado",
"layout_scroll": "Rolagem",
"navigation_mode": "Modo de navegação",
"navigation_options": {
"both": "Ambos",
"buttons": "Botões",
"click": "Clique / Toque"
},
"page_margins": "Margem de Páginas",
"viewing_theme": "Tema de visualização"
},
"shortcuts": {
"cycle_pagination": "Contagem de colunas do ciclo",
"cycle_viewing_theme": "Tema de visualização do ciclo",
"font_size_decrease": "Diminuir tamanho da fonte",
"font_size_increase": "Aumentar tamanho da fonte",
"menus": "Menus",
"next": "Avançar",
"previous": "Voltar",
"reader_navigation": "Navegação do leitor",
"scroll": "Altere o layout para rolagem",
"settings": "Configurações",
"show_hide_toc": "Mostrar/ocultar índice"
}
},
"error_codes": {
@ -686,18 +819,37 @@
"ERR_1023": "Livro já presente na Lista de Leitura",
"ERR_1024": "Erro de login OAuth2: nenhum atributo de e-mail",
"ERR_1025": "Erro de login OAuth2: não existe nenhum usuário local com esse e-mail",
"ERR_1026": "Erro de login do OpenID Connect: e-mail não verificado"
"ERR_1026": "Erro de login do OpenID Connect: e-mail não verificado",
"ERR_1027": "Erro de login OpenID Connect: o atributo email_verified está ausente",
"ERR_1028": "Erro de login OpenID Connect: o atributo email está ausente",
"ERR_1029": "O ComicRack CBL não contém nenhum elemento Book",
"ERR_1030": "O ComicRack CBL não contém nenhum elemento Name",
"ERR_1031": "ComicRack CBL Book está sem série ou número",
"ERR_1032": "O arquivo EPUB tem o tipo de mídia errado",
"ERR_1033": "Algumas entradas estão faltando",
"ERR_1034": "Uma chave de API com esse comentário já existe",
"ERR_1035": "Erro ao obter o EPUB TOC",
"ERR_1036": "Erro ao obter EPUB Landmarks",
"ERR_1037": "Erro ao obter a lista de páginas do EPUB",
"ERR_1038": "Erro ao obter páginas EPUB DIVINA",
"ERR_1039": "Erro ao obter posições do EPUB"
},
"filter": {
"age_rating": "classificação etária",
"age_rating_none": "Nenhuma",
"any": "Qualquer",
"complete": "Completo",
"genre": "gênero",
"in_progress": "Em progresso",
"language": "idioma",
"library": "biblioteca",
"media_profile": "Perfil de mídia",
"media_status": "Estado da mídia",
"oneshot": "One-shot",
"publisher": "editora",
"read": "Lidos",
"release_date": "data de lançamento",
"sharing_label": "Etiqueta de compartilhamento",
"status": "estado",
"tag": "tag",
"unread": "Não Lidos"
@ -708,8 +860,13 @@
},
"history": {
"header": {
"book": "Livro"
}
"book": "Livro",
"date": "Data",
"details": "Detalhes",
"series": "Séries",
"type": "Tiopo"
},
"title": "Histórico"
},
"home": {
"theme": "Tema",
@ -717,6 +874,8 @@
},
"library_navigation": {
"browse": "Navegar",
"browse_books": "Livros",
"browse_series": "Séries",
"collections": "Coleções",
"readlists": "Listas de Leitura",
"recommended": "Recomendado"
@ -749,15 +908,34 @@
"empty_trash": "Esvaziar a lixeira",
"mark_read": "Marcar como lido",
"mark_unread": "Marcar como não lido",
"pin": "Fixar",
"refresh_metadata": "Atualizar metadados",
"scan_library_files": "Varrer arquivos na biblioteca",
"select_all": "Selecionar todas"
"scan_library_files": "Escanear arquivos da biblioteca",
"scan_library_files_deep": "Escanear arquivos da biblioteca (profundo)",
"select_all": "Selecionar todas",
"unpin": "Liberar"
},
"metrics": {
"library_books": "Livros por biblioteca",
"library_disk_space": "Espaço ocupado pela biblioteca",
"library_series": "Série por biblioteca",
"library_sidecars": "Arquivos auxiliares por biblioteca",
"tasks_executed": "Tarefas executadas",
"tasks_total_time": "Tempo total das tarefas",
"title": "Métricas"
},
"missing_posters": {
"title": "Posters Ausentes"
},
"navigation": {
"home": "Início",
"libraries": "Bibliotecas",
"logout": "Sair"
},
"no_libraries_pinned": {
"subtitle": "Você pode fixar uma biblioteca no menu de 3 pontos",
"title": "Nenhuma biblioteca fixada"
},
"page_not_found": {
"go_back_to_home_page": "Retornar à página inicial",
"page_does_not_exist": "A página que você procura não existe.",
@ -767,6 +945,12 @@
"less": "Ver menos",
"more": "Ver mais"
},
"readlist_import": {
"row": {
"duplicate_book": "Duplicar livro",
"error_choose_book": "Escolha um livro"
}
},
"readlists_expansion_panel": {
"manage_readlist": "Gerenciar lista de leitura",
"title": "Lista de leitura: {name}"
@ -787,17 +971,41 @@
"button_cancel_all_tasks": "Cancelar todas as tarefas",
"button_empty_trash": "Limpar a lixeira de todas as bibliotecas",
"button_scan_libraries": "Escanear todas as bibliotecas",
"button_scan_libraries_deep": "Escanear todas bibliotecas (profundo)",
"button_shutdown": "Desligar",
"download_log": "Baixar arquivo de log",
"notification_tasks_cancelled": "Nenhuma tarefa para cancelar | Uma tarefa cancelada | {count} tarefas canceladas",
"section_title": "Gerenciamento do Servidor"
},
"tab_title": "Servidor"
"tab_title": "Servidor",
"updates": "Atualizações"
},
"server_settings": {
"config_precedence": "Prevalece sobre o arquivo de configuração",
"dialog_regenerate_thumbnails": {
"body": "O tamanho das miniaturas mudou. Deseja gerar novamente as miniaturas dos livros?",
"btn_alternate": "Sim, de todos os livros",
"btn_cancel": "Não",
"btn_confirm": "Sim, mas apenas se tiverem aumentado",
"title": "Gerar miniaturas novamente"
},
"hint_kobo_port": "Definir apenas em caso de problemas de sincronização com capas e downloads",
"label_delete_empty_collections": "Exclua coleções vazias depois do escaneamento",
"label_delete_empty_readlists": "Exclua listas de leitura vazias depois do escaneamento",
"label_kepubify_path": "Localização do kepubify",
"label_kobo_port": "Porta externa do Kobo Sync",
"label_kobo_proxy": "Proxy Kobo Sync para sincronização com a Kobo Store",
"label_rememberme_duration": "Duração do Lembrar de mim (em dias)",
"label_server_context_path": "URL Base",
"label_server_port": "Porta do servidor",
"label_task_pool_size": "Threads de tarefas",
"label_thumbnail_size": "Tamanho das miniaturas",
"requires_restart": "Requer reinicialização para entrar em vigor",
"server_settings": "Configurações do Servidor"
},
"settings_user": {
"change_password": "Alterar senha",
"edit_restrictions": "Editar restrições",
"edit_user": "Editar Usuário",
"latest_activity": "Última atividade: {date}",
"no_recent_activity": "Nenhuma atividade recente",
@ -807,13 +1015,17 @@
"sort": {
"books_count": "Total de livros",
"date_added": "Data de adição",
"date_read": "Data de leitura",
"date_updated": "Data de atualização",
"file_name": "Nome do arquivo",
"file_size": "Tamanho do arquivo",
"folder_name": "Nome da pasta",
"name": "Nome",
"number": "Número",
"release_date": "Data de lançamento"
"page_count": "Quantidade de páginas",
"random": "Aleatório",
"release_date": "Data de lançamento",
"series": "Séries"
},
"theme": {
"dark": "Escuro",
@ -822,6 +1034,7 @@
},
"thumbnail_card": {
"tooltip_delete": "Excluir",
"tooltip_generated": "Arte gerada",
"tooltip_mark_as_selected": "Marcar como selecionado",
"tooltip_selected": "Selecionado",
"tooltip_sidecar": "Mídia local",
@ -830,16 +1043,47 @@
"tooltip_too_big": "Arquivo muito grande!",
"tooltip_user_uploaded": "Enviado pelo usuário"
},
"titles_more": {
"less": "Menos títulos",
"more": "Mais títulos"
},
"ui_settings": {
"general": "Geral",
"label_oauth2_auto_login": "Login OAuth2 automático",
"label_oauth2_hide_login": "Ocultar campos de login se OAuth2 estiver ativado",
"label_poster_blur_unread": "Desfocar poster de livros e séries não lidos",
"label_poster_stretch": "Esticar pôster para ajustar ao card",
"label_series_groups": "Agrupamento de séries",
"section_oauth2": "OAuth2",
"series_groups": {
"alpha": "Alfabética",
"japanese": "Gojūon (japonês)"
},
"tooltip_oauth2_auto_login": "É necessário um único provedor OAuth2 e a ativação de 'ocultar campos de login'"
},
"updates": {
"available": "Atualizações disponiveis",
"latest_installed": "A versão mais recente do Komga já está instalada"
},
"user_roles": {
"ADMIN": "Administrador",
"FILE_DOWNLOAD": "Baixar arquivos",
"KOBO_SYNC": "Kobo Sync",
"KOREADER_SYNC": "KOReader Sync",
"PAGE_STREAMING": "Streaming de páginas",
"USER": "Usuário"
},
"users": {
"api_keys": "Chaves API",
"authentication_activity": "Atividade de Autenticação",
"users": "Usuários"
},
"validation": {
"context_path": "Deve começar com '/', não terminar com '/-_' e conter apenas '/-_a-z0-9'",
"one_or_more": "Deve ser 1 ou mais",
"tcp_port": "Deve estar entre 1 e 65535",
"zero_or_more": "Deve ser 0 ou mais"
},
"welcome": {
"add_library": "Adicionar biblioteca",
"no_libraries_yet": "Ainda não foram adicionadas bibliotecas!",

View file

@ -4,8 +4,8 @@
"pageText": "{0}-{1} из {2}"
},
"dataIterator": {
"loadingText": "Загрузка объектов...",
"noResultsText": "Подходящих записей не найдено"
"loadingText": "Загрузка элементов...",
"noResultsText": "Совпадений не найдено"
},
"dataTable": {
"itemsPerPageText": "Строк на странице:",
@ -15,30 +15,33 @@
"counter": "Файлов: {0}",
"counterSize": "Файлов: {0} (всего {1})"
},
"noDataText": "Отсутствуют данные"
"noDataText": "Данные отсутствуют"
},
"account_settings": {
"account_settings": "Настройки Аккаунта",
"account_settings": "Настройки аккаунта",
"api_key": {
"created_date": "Дата создания: {date}",
"generate_api_key": "Сгенерировать API ключ",
"force_kobo_sync": "Принудительная синхронизация с Kobo",
"generate_api_key": "Сгенерировать ключ API",
"no_keys": "Ни одного ключа API еще не создано"
},
"change_password": "изменить пароль"
"change_password": "изменить пароль",
"details": "Подробности",
"my_account": "Мой аккаунт"
},
"announcements": {
"mark_all_read": "Пометить всё как прочитанное",
"mark_read": "Пометить как прочитанное",
"mark_all_read": "Отметить всё как прочитанное",
"mark_read": "Отметить как прочитанное",
"tab_title": "Объявления"
},
"authentication_activity": {
"api_key": "API Ключ",
"datetime": "Дата / Время",
"api_key": "APIлюч",
"datetime": "Дата/Время",
"email": "Эл. почта",
"error": "Ошибка",
"ip": "IP-адрес",
"source": "Источник",
"success": "Статус",
"success": "Успех",
"user_agent": "User Agent"
},
"author_roles": {
@ -54,18 +57,18 @@
"book_card": {
"error": "Ошибка",
"no_release_date": "Дата релиза отсутствует",
"unknown": "Необходимо проанализировать",
"unknown": "Подлежит анализу",
"unread": "Не прочитано",
"unsupported": "Неподдерживаемый"
"unsupported": "Не поддерживается"
},
"book_import": {
"button_browse": "Обзор",
"button_import": "Импортировать",
"button_import": "Импорт",
"button_scan": "Сканировать",
"button_select_series": "Выберите Серию",
"button_select_series": "Выберите серию",
"field_import_path": "Импортировать из каталога",
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие Серии, в этом случае Komga переместит или скопирует файлы в каталог выбранной Серии.",
"info_part2": "Если вы выберете номер для книги и книга с таким номером уже существует, то вы сможете сравнить 2 книги. Если вы решите импортировать книгу, Komga обновит существующую книгу, эффективно заменив старый файл новым.",
"info_part1": "Этот раздел позволяет вам импортировать файлы, которые находятся за пределами ваших существующих библиотек. Вы можете импортировать файлы только в существующие серии; в этом случае Komga переместит или скопирует файлы в каталог выбранной серии.",
"info_part2": "Если вы укажете номер для книги, и книга с таким номером уже существует, вы сможете сравнить оба варианта. Если вы решите импортировать книгу, Komga обновит существующий вариант, заменив старый файл новым.",
"no_files_found": "Файлы не найдены",
"notification": {
"go_to_book": "Перейти к книге",
@ -74,9 +77,9 @@
"source_file": "Исходный файл: {file}"
},
"row": {
"error_analyze_first": "Книгу нужно сначала проанализировать",
"error_analyze_first": "Книга нуждается в предварительном анализе",
"error_choose_series": "Выберите серию",
"error_only_import_no_errors": "Можно импортировать только книги без ошибок",
"error_only_import_no_errors": "Можно импортировать только книги без наличия ошибок",
"warning_upgrade": "Существующая книга будет обновлена"
},
"table": {
@ -90,10 +93,11 @@
},
"bookreader": {
"beginning_of_book": "Вы находитесь в начале книги.",
"changing_reading_direction": "Изменение Направления Чтения на",
"cycling_page_layout": "Переключить Формат Страниц",
"cycling_scale": "Переключить Масштабирование",
"cycling_side_padding": "Переключить Боковой Отступ",
"changing_reading_direction": "Изменение направления чтения на",
"cycling_page_layout": "Переключение макета страницы",
"cycling_page_margin": "Переключение полей страницы",
"cycling_scale": "Масштабирование",
"cycling_side_padding": "Переключение боковых отступов",
"download_current_page": "Скачать текущую страницу",
"end_of_book": "Вы достигли конца книги.",
"from_series_metadata": "из метаданных серии",
@ -104,8 +108,8 @@
"notification_poster_set_readlist": "Текущая страница теперь используется в качестве постера списка чтения.",
"notification_poster_set_series": "Текущая страница теперь используется в качестве постера серии.",
"paged_reader_layout": {
"double": "Двойные страницы",
"double_no_cover": "Двойные страницы (без обложки)",
"double": "Две страницы",
"double_no_cover": "Две страницы (без обложки)",
"single": "Одна страница"
},
"reader_settings": "Настройки Ридера",
@ -114,16 +118,16 @@
"continuous_width": "По ширине",
"height": "По высоте",
"original": "Исходное",
"screen": "По экрану",
"screen": "По размеру экрана",
"width": "По ширине",
"width_shrink_only": "По ширине (с отступами)"
},
"set_current_page_as_book_poster": "Установить страницу в качестве постера для книги",
"set_current_page_as_readlist_poster": "Установить страницу в качестве постера для списка чтения",
"set_current_page_as_series_poster": "Установить страницу в качестве постера для серии",
"set_current_page_as_book_poster": "Установить страницу в качестве обложки для книги",
"set_current_page_as_readlist_poster": "Установить страницу в качестве обложки для списка чтения",
"set_current_page_as_series_poster": "Установить страницу в качестве обложки для серии",
"settings": {
"always_fullscreen": "Всегда в полный экран",
"animate_page_transitions": "Анимировать переходы страниц",
"always_fullscreen": "Всегда полноэкранный режим",
"animate_page_transitions": "Анимировать переходы между страницами",
"background_color": "Цвет фона",
"background_colors": {
"black": "Чёрный",
@ -134,54 +138,60 @@
"general": "Общее",
"gestures": "Жесты",
"page_layout": "Формат страницы",
"paged": "Настройки Отображения Страниц",
"page_margin": "Поля страницы",
"paged": "Настройки отображения страниц",
"reading_mode": "Режим чтения",
"scale_type": "Масштабирование",
"side_padding": "Боковой отступ",
"side_padding": "Боковые отступы",
"side_padding_none": "Нет",
"webtoon": "Параметры Режима Webtoon"
"webtoon": "Настройки режима цифрового комикса"
},
"shortcuts": {
"close": "Закрыть",
"cycle_page_layout": "Переключить формат страниц",
"cycle_page_layout": "Переключить макет страницы",
"cycle_page_margin": "Переключить поля страницы",
"cycle_scale": "Переключить масштаб",
"cycle_side_padding": "Переключить боковой отступ",
"cycle_side_padding": "Переключить боковые отступы",
"first_page": "Первая страница",
"fullscreen": "Войти/выйти из полноэкранного режима",
"last_page": "Последняя страница",
"left_to_right": "Слева Направо",
"left_to_right": "Слева направо",
"menus": "Меню",
"next_page": "Следующая страница",
"previous_page": "Предыдущая страница",
"reader_navigation": "Навигация",
"right_to_left": "Справа Налево",
"right_to_left": "Справа налево",
"settings": "Настройки",
"show_hide_help": "Показать/скрыть помощь",
"show_hide_settings": "Показать/скрыть меню настроек",
"show_hide_thumbnails": "Показать/скрыть просмотр эскизов",
"show_hide_thumbnails": "Показать/скрыть обозреватель миниатюр",
"show_hide_toolbars": "Показать/скрыть панели инструментов",
"vertical": "Вертикально",
"webtoon": "Webtoon"
"webtoon": "Цифровой комикс"
},
"tooltip_incognito": "Прогресс чтения не будет сохранен"
},
"browse_book": {
"comment": "КОММЕНТАРИЙ",
"date_created": "СОЗДАНО",
"date_modified": "ПОСЛЕДНЕЕ ИЗМЕНЕНИЕ",
"download_file": "Скачать файл",
"file": "ФАЙЛ",
"format": "ФОРМАТ",
"isbn": "ISBN",
"links": "ССЫЛКИ",
"navigation_within_readlist": "Навигация в пределах списка чтения: {name}",
"outdated_tooltip": "Файл этой книги изменен, книгу необходимо повторно проанализировать",
"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": "ручной порядок"
"manual_ordering": "ручная сортировка"
},
"browse_readlist": {
"edit_elements": "Редактировать элементы",
@ -189,17 +199,19 @@
"manual_ordering": "ручная сортировка"
},
"browse_series": {
"earliest_year_from_release_dates": "Это самая ранняя дата выпуска из всех книг в этой серии",
"series_no_summary": "У серии нет описания, поэтому мы подобрали его для вас!",
"earliest_year_from_release_dates": "Это самый ранний год из дат выхода всех книг серии",
"remove_from_collection": "Удалить серию из коллекции",
"series_no_summary": "У этой серии нет описания, поэтому мы подобрали его для вас!",
"summary_from_book": "Краткое описание из книги {number}:"
},
"collections_expansion_panel": {
"manage_collection": "Управлять коллекцией",
"manage_collection": "Управление коллекцией",
"title": "Коллекция {name}"
},
"common": {
"age": "Возраст",
"all_libraries": "Все Библиотеки",
"all_libraries": "Все библиотеки",
"any_of": "Любой из",
"book": "Книга",
"books": "Книги",
"books_n": "Книг нет | 1 книга | {count} книг",
@ -212,14 +224,16 @@
"copied": "Скопировано!",
"create": "Создать",
"delete": "Удалить",
"dimension": "шир.: {width} выс.: {height}",
"dimension": "шир.: {width}, выс.: {height}",
"discard": "Отмена",
"disk_space": "Дисковое пространство",
"dismiss": "Отклонить",
"download": "Скачать",
"drag_drop": "перетащить",
"duplicate": "Дублировать",
"email": "Эл. почта",
"epub": "Epub",
"error": "Ошибка",
"filename": "Имя файла",
"filter_no_matches": "Нет совпадений по заданному фильтру",
"genre": "Жанр",
@ -227,12 +241,16 @@
"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": "OK",
"outdated": "Устарело",
"page": "Страница",
"page_number": "Номер страницы",
@ -242,17 +260,20 @@
"password": "Пароль",
"pdf": "PDF",
"pending_tasks": "Нет незавершенных задач | 1 незавершенная задача | {count} незавершенных задач",
"pinned_libraries": "Закреплённые библиотеки",
"publisher": "Издатель",
"read": "Читать",
"read_on": "Читать {date}",
"read_on": "Прочитано {date}",
"readlist": "Список чтения",
"readlists": "Списки чтения",
"remember-me": "Запомнить",
"required": "Необходимо",
"remember-me": "Запомнить меня",
"reorder": "Изменить порядок",
"required": "Обязательно",
"reset_filters": "Сбросить фильтры",
"roles": "Роли",
"save_changes": "Сохранить изменения",
"series": "Серии",
"settings": "Настройки",
"tags": "Теги",
"unavailable": "Недоступно",
"unlock_all": "Разблокировать все",
@ -326,7 +347,7 @@
"confirm_delete": "Да, удалить коллекцию \"{name}\"",
"confirm_delete_multiple": "Да, удалить выбранные ({count}) коллекции",
"dialog_title": "Удалить коллекцию",
"dialog_title_multiple": "Удалить Коллекции",
"dialog_title_multiple": "Удалить коллекции",
"warning_html": "Коллекция <b>{name}</b> будет удалена с этого сервера. Ваши медиа файлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?",
"warning_multiple_html": "Выбранные ({count}) коллекции будут удалены с этого сервера. Ваши медиафайлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?"
},
@ -340,8 +361,8 @@
"button_confirm": "Удалить",
"confirm_delete": "Да, удалить список чтения \"{name}\"",
"confirm_delete_multiple": "Да, удалить выбранные ({count}) списки чтения",
"dialog_title": "Удалить Список Чтения",
"dialog_title_multiple": "Удалить Списки чтения",
"dialog_title": "Удалить список чтения",
"dialog_title_multiple": "Удалить списки чтения",
"warning_html": "Список чтения <b>{name}</b> будет удален с этого сервера. Ваши медиа файлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?",
"warning_multiple_html": "Выбранные ({count}) списки чтения будут удалены с этого сервера. Ваши медиафайлы не будут затронуты. Это действие <b>не может</b> быть отменено. Продолжить?"
},
@ -355,32 +376,34 @@
"delete_user": {
"button_confirm": "Удалить",
"confirm_delete": "Да, удалить пользователя \"{name}\"",
"dialog_title": "Удалить Пользователя",
"warning_html": "Пользователь <b>{name}</b> буден удален с этого сервера. Это действие <b>не может</b> быть отменено. Продолжить?"
"dialog_title": "Удалить пользователя",
"warning_html": "Пользователь <b>{name}</b> буден удален с этого сервера. Это действие <b>нельзя</b> отменить. Продолжить?"
},
"edit_books": {
"add_author_role_error_duplicate": "Уже существует",
"authors_notice_multiple_edit": "Вы редактируете авторов для нескольких книг. Это действие перезапишет существующих авторов для каждой книги.",
"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_number": "Номер",
"field_number_sort": "Номер сортировки",
"field_number_sort": "Порядковый номер",
"field_number_sort_hint": "Вы можете использовать десятичные числа",
"field_release_date": "Дата выхода",
"field_release_date_error": "Дата должна быть в действительном YYYY-MM-DD формате",
"field_summary": "Краткое Описание",
"field_summary": "Аннотация",
"field_tags": "Теги",
"field_title": "Заголовок",
"tab_authors": "Авторы",
"tab_general": "Общее",
"tab_links": "Ссылки",
"tab_poster": "Постер",
"tab_poster": "Обложка",
"tab_tags": "Теги",
"tags_notice_multiple_edit": "Вы редактируете теги для нескольких книг. Это действие перзапишет существующие теги для каждой книги."
},
@ -388,8 +411,8 @@
"button_cancel": "Отмена",
"button_confirm": "Сохранить изменения",
"dialog_title": "Редактировать коллекцию",
"field_manual_ordering": "Ручной порядок",
"label_ordering": "По умолчанию серии в коллекции будут отсортированы по имени. Вы можете включить ручной порядок, чтобы указать собственный порядок.",
"field_manual_ordering": "Ручное упорядочивание",
"label_ordering": "По умолчанию серии в коллекции упорядочиваются по названию. Вы можете включить ручную сортировку, чтобы задать собственный порядок.",
"tab_general": "Общее",
"tab_poster": "Постер"
},
@ -399,76 +422,90 @@
"button_confirm_add": "Добавить",
"button_confirm_edit": "Редактировать",
"button_next": "Далее",
"dialog_title_add": "Добавить Библиотеку",
"dialot_title_edit": "Редактировать Библиотеку",
"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_barcode_isbn": "ISBN штрих-код",
"field_import_comicinfo_book": "Метаданные книг",
"field_import_comicinfo_collections": "Коллекции",
"field_import_comicinfo_readlists": "Списки чтения",
"field_import_comicinfo_series": "Метаданные серий",
"field_import_epub_book": "Метаданные книг",
"field_import_epub_series": "Метаданные серий",
"field_import_comicinfo_series_append_volume": "Включать том в название серии",
"field_import_epub_book": "Метаданные книги",
"field_import_epub_series": "Метаданные серии",
"field_import_local_artwork": "Локальные обложки",
"field_import_mylar_series": "Метаданные серий",
"field_import_mylar_series": "Метаданные серии",
"field_name": "Имя",
"field_oneshotsdirectory": "Каталог для ваншотов",
"field_repair_extensions": "Автоматическое исправление неправильных расширений файлов",
"field_root_folder": "Корневой каталог",
"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_barcode_isbn": "Импорт ISBN через штрих-код",
"label_import_comicinfo": "Импорт метаданных для CBR/CBZ, содержащих файл ComicInfo.xml",
"label_import_epub": "Импорт метаданных из EPUB файлов",
"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_scanner_force_modified_time": "Включите если библиотека размещена на Google Drive",
"tooltip_use_resources": "Может потреблять много ресурсов на больших библиотеках или медленном оборудовании"
"tooltip_oneshotsdirectory": "Оставьте пустым для отключения",
"tooltip_scanner_force_modified_time": "Включите, если библиотека размещена на Google Drive",
"tooltip_use_resources": "Может потреблять много ресурсов при работе с большими библиотеками или на слабом оборудовании"
},
"edit_readlist": {
"button_cancel": "Отмена",
"button_confirm": "Сохранить изменения",
"dialog_title": "Редактировать список чтения",
"field_manual_ordering": "Ручная сортировка",
"field_name": "Имя",
"field_summary": "Сводка",
"field_summary": "Аннотация",
"label_ordering": "По умолчанию книги в списке чтения упорядочиваются вручную. Вы можете отключить ручную сортировку, чтобы упорядочить книги по дате выхода.",
"tab_general": "Общее",
"tab_poster": "Постер"
"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_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_reading_direction": "Направление чтения",
"field_sort_title": "Сортировать по названию",
"field_status": "Статус",
"field_summary": "Краткое Описание",
"field_summary": "Краткое описание",
"field_tags": "Теги",
"field_title": "Название",
"field_total_book_count": "Общее Количество Книг",
"field_total_book_count_error": "Общее количество книг может быть 1 или более",
"field_total_book_count": "Общее количество книг",
"field_total_book_count_error": "Общее количество книг может быть большим или равным 1",
"mixed": "СМЕШАННЫЙ",
"tab_general": "Общее",
"tab_poster": "Постер",
"tab_poster": "Обложка",
"tab_tags": "Теги",
"tags_notice_multiple_edit": "Вы редактируете теги для нескольких серий. Это действие перезапишет существующие теги для каждой серии."
},
@ -483,12 +520,14 @@
"none": "Без ограничений"
},
"edit_restrictions_for": "Редактировать ограничения для {name}",
"label_age_restriction": "Ограничение по возрасту",
"label_age_restriction": "Возрастное ограничение",
"label_allow_only_labels": "Разрешить только метки",
"label_exclude_labels": "Исключить метки"
"label_exclude_labels": "Исключить метки",
"tab_content_restrictions": "Ограничения контента",
"tab_shared_libraries": "Общие библиотеки"
},
"empty_trash": {
"body": "По умолчанию медиа-сервер не удаляет информацию для медиа сразу. Это помогает, если диск временно отключен. Когда вы очищаете корзину для библиотеки, вся информация об отсутствующих медиафайлах удаляется.",
"body": "По умолчанию медиасервер не удаляет информацию о медиафайлах сразу. Это помогает, если диск был временно отключён. При очистке корзины библиотеки удаляется вся информация об отсутствующих медиафайлах.",
"button_confirm": "Очистить",
"title": "Очистить корзину для библиотеки"
},
@ -496,17 +535,17 @@
"button_cancel": "Отмена",
"button_confirm_default": "Выбрать",
"dialog_title_default": "Обозреватель файлов",
"parent_directory": "Родитель"
"parent_directory": "Родительский каталог"
},
"filename_chooser": {
"button_choose": "Выбрать",
"field_destination_filename": "Имя файла назначения",
"label_source_filename": "Исходное имя файла",
"table": {
"existing_file": "Существующий Файл",
"existing_file": "Существующий файл",
"order": "Порядок"
},
"title": "Имя Файла Назначения"
"title": "Имя файла назначения"
},
"password_change": {
"button_cancel": "Отмена",
@ -524,6 +563,7 @@
},
"series_picker": {
"label_search_series": "Поиск Серии",
"no_results": "No Series found",
"title": "Выберите Серию"
},
"server_stop": {
@ -612,44 +652,97 @@
"ONGOING": "Выпускается"
}
},
"epubreader": {
"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": "Multi-Volume RAR архивы не поддерживаются",
"ERR_1005": "Неизвестная ошибка при анализе книги",
"ERR_1001": "Тип медиафайла не поддерживается",
"ERR_1002": "Зашифрованные RAR-архивы не поддерживаются",
"ERR_1003": "Непрерывные RAR-архивы не поддерживаются",
"ERR_1004": "Многотомные RAR-архивы не поддерживаются",
"ERR_1005": "Неизвестная ошибка в процессе анализа книги",
"ERR_1006": "Книга не содержит ни одной страницы",
"ERR_1007": "Некоторые записи не могут быть проанализированы",
"ERR_1008": "Неизвестная ошибка при получении записей книги",
"ERR_1007": "Некоторые записи не удалось проанализировать",
"ERR_1008": "Неизвестная ошибка в процессе получения записей книги",
"ERR_1009": "Список чтения с таким именем уже существует",
"ERR_1015": "Ошибка при десериализации Списка чтения ComicRack",
"ERR_1015": "Ошибка при десериализации CBL-файла ComicRack",
"ERR_1016": "Каталог недоступен или не является каталогом",
"ERR_1017": "Невозможно просканировать папку, которая является частью существующей библиотеки",
"ERR_1018": "Файл не найден",
"ERR_1019": "Невозможно импортировать файл, который является частью существующей библиотеки",
"ERR_1020": "Книга для обновления не относится к указанной серии",
"ERR_1020": "Книга для обновления не принадлежит указанной серии",
"ERR_1021": "Файл назначения уже существует",
"ERR_1022": "Недавно импортированная книга не может быть отсканирована"
"ERR_1022": "Недавно импортированную книгу не удалось просканировать",
"ERR_1023": "Книга уже присутствует в списке чтения",
"ERR_1024": "Ошибка входа через OAuth2: отсутствует атрибут 'email'",
"ERR_1025": "Ошибка входа через OAuth2: локальный пользователь с таким email не существует",
"ERR_1026": "Ошибка входа через OpenID Connect: email не подтверждён",
"ERR_1027": "Ошибка входа через OpenID Connect: отсутствует атрибут 'email_verified'",
"ERR_1028": "Ошибка входа через OpenID Connect: отсутствует атрибут 'email'",
"ERR_1029": "CBL-файл ComicRack не содержит ни одного элемента 'Book'",
"ERR_1030": "В CBL-файле ComicRack отсутствует элемент 'Name'",
"ERR_1031": "В элементе 'Book' CBL-файла ComicRack отсутствует серия или номер",
"ERR_1032": "Файл EPUB имеет неверный медиа-тип",
"ERR_1033": "Некоторые записи отсутствуют",
"ERR_1034": "Ключ API с таким комментарием уже существует",
"ERR_1035": "Ошибка при получении оглавления EPUB",
"ERR_1036": "Ошибка при получении навигационных меток EPUB",
"ERR_1037": "Ошибка при получении списка страниц EPUB",
"ERR_1038": "Ошибка при получении страниц divina в EPUB",
"ERR_1039": "Ошибка при получении позиций в EPUB"
},
"filter": {
"age_rating": "Возрастной Рейтинг",
"age_rating_none": "Нет",
"age_rating": "Возрастной рейтинг",
"age_rating_none": "Не задан",
"any": "Любой",
"complete": "Завершенные",
"genre": "жанр",
"in_progress": "Читаю",
"language": "язык",
"library": "библиотека",
"publisher": "издатель",
"genre": "Жанр",
"in_progress": "В процессе",
"language": "Язык",
"library": "Библиотека",
"media_profile": "Медиапрофиль",
"media_status": "Статус медиа",
"oneshot": "Ван-шот",
"publisher": "Издатель",
"read": "Прочитано",
"release_date": "дата выхода",
"status": "статус",
"tag": "тег",
"unread": "Непрочитанные"
"release_date": "Дата выхода",
"sharing_label": "Метка общего доступа",
"status": "Статус",
"tag": "Тег",
"unread": "Не прочитано"
},
"filter_drawer": {
"filter": "фильтр",
"sort": "сортировка"
"filter": "Фильтр",
"sort": "Сортировка"
},
"history": {
"header": {
@ -667,19 +760,21 @@
},
"library_navigation": {
"browse": "Обзор",
"browse_books": "Книги",
"browse_series": "Серии",
"collections": "Коллекции",
"readlists": "Списки Чтения",
"readlists": "Списки чтения",
"recommended": "Рекомендуемые"
},
"login": {
"create_user_account": "Создать аккаунт пользователя",
"create_user_account": "Создать учётную запись пользователя",
"login": "Войти",
"unclaimed_html": "Этот Komga сервер еще не активен, чтобы получить к нему доступ вам необходимо создать аккаунт пользователя.<br><br>Выберите <strong>эл. почту</strong> и <strong>пароль</strong> и нажмите на <strong>Создать аккаунт пользователя</strong>."
"unclaimed_html": "Этот сервер Komga еще не активtн: для доступа к нему необходимо создать учётную запись пользователя.<br><br>Выберите <strong>email</strong> и <strong>пароль</strong> и нажмите на <strong>Создать учетную запись пользователя</strong>."
},
"media_analysis": {
"comment": "Комментарий",
"media_analysis": "Медиа анализ",
"media_type": "Медиатип",
"media_analysis": "Медиаанализ",
"media_type": "Тип медиа",
"name": "Имя",
"size": "Размер",
"status": "Статус",
@ -689,6 +784,7 @@
"add_to_collection": "Добавить в коллекцию",
"add_to_readlist": "Добавить в список чтения",
"analyze": "Анализировать",
"bulk_edit_metadata": "Массовое редактирование метаданных",
"delete": "Удалить",
"deselect_all": "Отменить выбор",
"download_readlist": "Скачать список чтения",
@ -698,20 +794,34 @@
"empty_trash": "Очистить корзину",
"mark_read": "Отметить как прочитанное",
"mark_unread": "Пометить как непрочитанное",
"pin": "Закрепить",
"refresh_metadata": "Обновить метаданные",
"scan_library_files": "Сканировать файлы библиотеки",
"select_all": "Выбрать всё"
"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": "Искомая страница не существует.",
@ -721,12 +831,18 @@
"less": "Свернуть",
"more": "Подробнее"
},
"readlist_import": {
"row": {
"duplicate_book": "Дубликат книги",
"error_choose_book": "Выберите книгу"
}
},
"readlists_expansion_panel": {
"manage_readlist": "Управлять списком чтения",
"title": "Список чтения {name}"
},
"search": {
"no_results": "Поиск не вернул результатов",
"no_results": "Поиск не дал результатов",
"search": "Поиск",
"search_for_something_else": "Попробуйте поискать что-нибудь другое",
"search_results_for": "Результаты поиска по запросу \"{name}\""
@ -734,39 +850,68 @@
"searchbox": {
"in_library": "в {library}",
"no_results": "Ничего не найдено",
"search_all": "Найти все…"
"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": "Сервер"
"tab_title": "Сервер",
"updates": "Обновления"
},
"server_settings": {
"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",
"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}",
"latest_activity": "Последняя активность: {date}",
"no_recent_activity": "Не обнаружено недавней активности",
"role_administrator": "Администратор",
"role_user": "Пользователь"
},
"sort": {
"books_count": "Количество книг",
"date_added": "Дата добавления",
"date_updated": "Дата обновления",
"file_name": "Имя файла",
"file_size": "Размер файла",
"folder_name": "Имя каталога",
"name": "Имя",
"number": "Номер",
"release_date": "Дата выхода"
"books_count": "По количеству книг",
"date_added": "По дате добавления",
"date_read": "По дате прочтения",
"date_updated": "По дате обновления",
"file_name": "По имени файла",
"file_size": "По размеру файла",
"folder_name": "По имени каталога",
"name": "По имени",
"number": "По номеру",
"page_count": "По количеству страниц",
"random": "В случайном порядке",
"release_date": "По дате выхода",
"series": "По сериям"
},
"theme": {
"dark": "Тёмная",
@ -774,18 +919,57 @@
"system": "Системная"
},
"thumbnail_card": {
"tooltip_delete": "Удалить"
"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": {
"authentication_activity": "Проверка подлинности",
"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": "Библиотеки еще не были добавлены!",

View file

@ -19,7 +19,15 @@
},
"account_settings": {
"account_settings": "Kontoinställningar",
"change_password": "ändra lösenord"
"api_key": {
"created_date": "Skapades datum: {date}",
"force_kobo_sync": "Tvinga Kobo synk",
"generate_api_key": "Skapa API-nyckel",
"no_keys": "Inga API-nycklar skapade ännu"
},
"change_password": "ändra lösenord",
"details": "Detaljer",
"my_account": "Mitt konto"
},
"announcements": {
"mark_all_read": "Markera alla som lästa",
@ -27,6 +35,7 @@
"tab_title": "Annonseringar"
},
"authentication_activity": {
"api_key": "API-nyckel",
"datetime": "Datum & Tid",
"email": "E-post",
"error": "Fel",
@ -86,6 +95,7 @@
"beginning_of_book": "Du är i början av boken.",
"changing_reading_direction": "Byt läsriktning till",
"cycling_page_layout": "Växla Sidlayout",
"cycling_page_margin": "Växlar sidmarginal",
"cycling_scale": "Växla Skala",
"cycling_side_padding": "Växla Spaltfyllnad",
"download_current_page": "Ladda ner nuvarande sida",
@ -128,6 +138,7 @@
"general": "Generella",
"gestures": "Gester",
"page_layout": "Sidlayout",
"page_margin": "Sidmarginal",
"paged": "Inställningar för sidvisning",
"reading_mode": "Läsläge",
"scale_type": "Skal typ",
@ -138,6 +149,7 @@
"shortcuts": {
"close": "Stäng",
"cycle_page_layout": "Växla sidlayout",
"cycle_page_margin": "Växla sidmarginal",
"cycle_scale": "Växla skala",
"cycle_side_padding": "Växla sidofyllning",
"first_page": "Första sidan",
@ -161,6 +173,8 @@
},
"browse_book": {
"comment": "KOMMENTAR",
"date_created": "SKAPADES",
"date_modified": "SENAST ÄNDRAD",
"download_file": "Ladda ner fil",
"file": "FIL",
"format": "FORMAT",
@ -170,6 +184,8 @@
"outdated_tooltip": "Filen för den här boken har ändrats, boken måste analyseras om",
"read_book": "Läs bok",
"read_incognito": "Läs incognito",
"remove_from_collection": "Ta bort bok från samling",
"remove_from_readlist": "Ta bort bok från läslista",
"size": "STORLEK"
},
"browse_collection": {
@ -184,6 +200,7 @@
},
"browse_series": {
"earliest_year_from_release_dates": "Detta är det tidigaste året från utgivningsdatum från alla böcker i serien",
"remove_from_collection": "Ta bort serie från samling",
"series_no_summary": "Denna serie har ingen sammanfattning, så vi valde en för dig!",
"summary_from_book": "Sammanfattning från bok {number}:"
},
@ -194,21 +211,28 @@
"common": {
"age": "Ålder",
"all_libraries": "Alla bibliotek",
"all_of": "Samtliga",
"any_of": "Någon av",
"book": "Bok",
"books": "Böcker",
"books_n": "Ingen bok | 1 bok | {count} böcker",
"books_total": "{count} / {total} böcker",
"cancel": "Avbryt",
"cbx": "Serietidningsarkiv",
"choose_image": "Välj en bild",
"close": "Stäng",
"collections": "Samlingar",
"copied": "Kopierad!",
"create": "Skapa",
"delete": "Redera",
"dimension": "b: {width}, h: {height}",
"disk_space": "Diskutrymme",
"dismiss": "Avfärda",
"download": "Ladda ner",
"drag_drop": "dra och släpp",
"email": "E-post",
"epub": "Epub",
"error": "Fel",
"filename": "Filnamn",
"filter_no_matches": "Det aktiva filtret ger ingen träff",
"genre": "Genre",
@ -216,12 +240,16 @@
"go_to_library": "Gå till bibliotek",
"go_to_readlist": "Gå till läslistan",
"go_to_series": "Gå till serien",
"i_understand": "Jag förstår",
"library": "Bibliotek",
"locale_name": "Svenska",
"locale_rtl": "false",
"lock_all": "Lås alla",
"media": "Media",
"more": "Mer",
"n_selected": "{count} valda",
"nothing_to_show": "Inget att visa",
"ok": "OK",
"oneshot": "One-shot",
"outdated": "Föråldrad",
"page": "Sida",
@ -230,19 +258,25 @@
"pages_left": "Inga sidor kvar | 1 sida kvar | {count} sidor kvar",
"pages_n": "Inga sidor | 1 sida | {count} sidor",
"password": "Lösenord",
"pdf": "PDF",
"pending_tasks": "Inga väntande uppgifter | 1 väntande uppgift | {count} väntande uppgifter",
"pinned_libraries": "Fästa Bibliotek",
"publisher": "Utgivare",
"read": "Läs",
"read_on": "Läst den {date}",
"readlist": "Läslista",
"readlists": "Läslistor",
"remember-me": "Kom ihåg mig",
"reorder": "Ordna om",
"required": "Krävs",
"reset_filters": "Återställ filter",
"roles": "Roller",
"save_changes": "Spara ändringar",
"series": "Serier | Serier",
"settings": "Inställningar",
"sidecars": "Sidovagnar",
"tags": "Taggar",
"ui": "Gränssnitt",
"unavailable": "Otillgänglig",
"unlock_all": "Lås upp alla",
"url": "URL",
@ -281,6 +315,11 @@
"tab_title": "Data import"
},
"dialog": {
"add_api_key": {
"context": "API-nycklar kan användas för autentisering via Kobo Synkprotokoll.",
"dialog_title": "Skapa ny API-nyckel",
"field_comment": "Kommentar"
},
"add_to_collection": {
"button_create": "Skapa",
"card_collection_subtitle": "Ingen serie | 1 serie | {count} serier",
@ -314,6 +353,12 @@
"filter": "Filtrera efter boknummer, titel, eller utgivningsdatum",
"title": "Välj bok"
},
"delete_apikey": {
"button_confirm": "Radera",
"confirm_delete": "Jag förstår, radera API-nyckel \"{name}\"",
"dialog_title": "Radera API-nyckel",
"warning_html": "Applikationer eller skript som använder denna API-nyckel kommer inte längre kunna nyttja Komga API:et. Det går ej att ångra denna åtgärd."
},
"delete_book": {
"button_confirm": "Ta bort",
"confirm_delete": "Ja, radera boken \"{name}\" och dess filer",
@ -456,10 +501,13 @@
"field_manual_ordering": "Manuell sortering",
"field_name": "Namn",
"field_summary": "Sammanfattning",
"label_ordering": "Som standard, böcker i en läslista sorteras manuellt. Du kan inaktivera manuell sortering för att sortera böcker efter släppdatum.",
"label_ordering": "Som standard sorteras böcker i en läslista manuellt. Du kan inaktivera manuell sortering för att sortera böcker efter släppdatum.",
"tab_general": "Allmänt",
"tab_poster": "Affisch"
},
"edit_recommended": {
"button_confirm": "Spara ändringar"
},
"edit_series": {
"button_cancel": "Avbryt",
"button_confirm": "Spara ändringar",
@ -528,6 +576,10 @@
},
"title": "Namn på målfil"
},
"force_kobo_sync": {
"dialog_title": "Tvinga Kobo synk",
"warning_html": "Detta raderar all synkhistorik för denna API-nyckel. Din Kobo kommer synka allt vid nästa synktillfälle."
},
"password_change": {
"button_cancel": "Avbryt",
"button_confirm": "Ändra lösenord",
@ -597,6 +649,8 @@
"empty_title": "Inga dubbletter av sidor hittades",
"filter": {
"count": "Antal",
"date_added": "Datum tillagd",
"date_modified": "Datum ändrad",
"delete_count": "Antal gånger raderat",
"delete_size": "Sparat utrymme",
"match_count": "Matcha antal",
@ -622,6 +676,23 @@
"HARDLINK": "Hårdlänk/kopiera filer",
"MOVE": "Flytta filer"
},
"epubreader": {
"appearances": {
"day": "Dag",
"night": "Natt",
"sepia": "Sepia"
},
"column_count": {
"auto": "Auto",
"one": "En",
"two": "Två"
},
"reading_direction": {
"auto": "Automatisk",
"ltr": "Vänster till höger",
"rtl": "Höger till vänster"
}
},
"historical_event_type": {
"BookConverted": "Boken konverterad",
"BookFileDeleted": "Bokfilen raderad",
@ -629,6 +700,11 @@
"DuplicatePageDeleted": "Duplicerad sida borttagen",
"SeriesFolderDeleted": "Seriemappen borttagen"
},
"media_profile": {
"DIVINA": "DIVINA",
"EPUB": "EPUB",
"PDF": "PDF"
},
"media_status": {
"ERROR": "Fel",
"OUTDATED": "Föråldrad",
@ -647,6 +723,14 @@
"VERTICAL": "Lodrät",
"WEBTOON": "Webtoon"
},
"scan_interval": {
"DAILY": "Varje dag",
"DISABLED": "Inaktiverad",
"EVERY_12H": "Varje 12 timmar",
"EVERY_6H": "Varje 6 timmar",
"HOURLY": "Varje timme",
"WEEKLY": "Varje vecka"
},
"series_cover": {
"FIRST": "Första",
"FIRST_UNREAD_OR_FIRST": "Första olästa annars första",
@ -658,6 +742,34 @@
"ENDED": "Avslutad",
"HIATUS": "Hiatus",
"ONGOING": "Pågående"
},
"thumbnail_size": {
"LARGE": "Stor (900px)",
"MEDIUM": "Mellan (600px)"
}
},
"epubreader": {
"current_chapter": "Nuvarande kapitel",
"page_of": "Sida {page} av {count}",
"publisher_font": "Utgivare",
"settings": {
"font_family": "Teckensnitt",
"layout": "Layout",
"layout_paginated": "Paginerad",
"navigation_mode": "Navigeringsläge",
"navigation_options": {
"buttons": "Knappar"
},
"page_margins": "Sidmarginal",
"viewing_theme": "Visningstema"
},
"shortcuts": {
"cycle_viewing_theme": "Växla visningstema",
"font_size_decrease": "Minska storlek på teckensnitt",
"font_size_increase": "Öka storlek på teckensnitt",
"menus": "Menyer",
"settings": "Inställningar",
"show_hide_toc": "Visa/dölj innehållsförteckning"
}
},
"error_codes": {

View file

@ -425,7 +425,7 @@
"field_isbn_error": "செல்லுபடியாகும் ISBN 13 ஆக இருக்க வேண்டும்",
"field_link_label": "சிட்டை",
"field_link_url": "முகவரி",
"field_link_url_error_protocol": "HTTP அல்லது HTTPS ஆக இருக்க வேண்டும்",
"field_link_url_error_protocol": "http அல்லது https ஆக இருக்க வேண்டும்",
"field_link_url_error_url": "செல்லுபடியாகும் முகவரி ஆக இருக்க வேண்டும்",
"field_number": "எண்",
"field_number_sort": "வரிசை எண்",

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@
"no_keys": "尚未创建 API 密钥"
},
"change_password": "更改密码",
"details": "详",
"details": "详细信息",
"my_account": "我的账户"
},
"announcements": {
@ -636,7 +636,7 @@
"size": "文件大小",
"width": "宽"
},
"title": "书籍详",
"title": "书籍详细信息",
"title_comparison": "书籍比较"
},
"transient_book_viewer": {
@ -862,7 +862,7 @@
"header": {
"book": "书籍",
"date": "日期",
"details": "详",
"details": "详细信息",
"series": "系列",
"type": "类型"
},
@ -916,9 +916,9 @@
"unpin": "取消固定"
},
"metrics": {
"library_books": "每个库的书籍数",
"library_disk_space": "库磁盘空间",
"library_series": "每个库的系列数",
"library_books": "每个库的书籍数",
"library_disk_space": "每个库磁盘空间占用",
"library_series": "每个库的系列数",
"library_sidecars": "每个库的边车",
"tasks_executed": "已执行的任务",
"tasks_total_time": "任务总时间",
@ -1051,7 +1051,7 @@
"general": "常规",
"label_oauth2_auto_login": "自动 OAuth2 登录",
"label_oauth2_hide_login": "如果启用了 OAuth2则隐藏登录字段",
"label_poster_blur_unread": "未读书籍和系列模糊海报",
"label_poster_blur_unread": "未读书籍和系列模糊海报",
"label_poster_stretch": "拉伸海报以适合卡片",
"label_series_groups": "系列分组",
"section_oauth2": "OAuth2",

View file

@ -751,7 +751,7 @@ export default Vue.extend({
const fontFamiliesInjectables = this.fontFamiliesAdditional.map(x => ({
type: 'style',
url: new URL(`${urls.origin}api/v1/fonts/resource/${x}/css`, import.meta.url).toString(),
url: new URL(`${urls.origin}api/v1/fonts/resource/${x}/css`).toString(),
fontFamily: x,
}))

View file

@ -78,7 +78,7 @@ dependencies {
implementation("org.apache.tika:tika-core:2.9.1")
implementation("org.apache.commons:commons-compress:1.27.1")
implementation("com.github.junrar:junrar:7.5.5")
implementation("com.github.junrar:junrar:7.6.0")
implementation("com.github.gotson.nightcompress:nightcompress:1.1.1")
implementation("org.apache.pdfbox:pdfbox:3.0.5")
implementation("net.grey-panther:natural-comparator:1.1")
@ -394,6 +394,7 @@ openApi {
args.add("--spring.profiles.active=claim,generate-openapi")
args.add("--server.port=8080")
}
waitTimeInSeconds.set(60)
}
tasks.jacocoTestReport {

View file

@ -1,11 +1,11 @@
FROM eclipse-temurin:17-jre as builder
FROM eclipse-temurin:17-jre AS builder
ARG JAR={{distributionArtifactFile}}
WORKDIR /builder
COPY assembly/${JAR} application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
# amd64 builder
FROM ubuntu:24.10 as build-amd64
FROM ubuntu:26.04 AS build-amd64
ENV JAVA_HOME=/opt/java/openjdk
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
ENV PATH="${JAVA_HOME}/bin:${PATH}"
@ -19,7 +19,7 @@ RUN apt -y update && \
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/lib/x86_64-linux-gnu"
# arm64 builder
FROM ubuntu:24.10 as build-arm64
FROM ubuntu:26.04 AS build-arm64
ENV JAVA_HOME=/opt/java/openjdk
COPY --from=eclipse-temurin:23-jre $JAVA_HOME $JAVA_HOME
ENV PATH="${JAVA_HOME}/bin:${PATH}"
@ -33,7 +33,7 @@ RUN apt -y update && \
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/lib/aarch64-linux-gnu"
# arm builder: uses temurin-17, as arm32 support was dropped in JDK 21
FROM eclipse-temurin:17-jre as build-arm
FROM eclipse-temurin:17-jre AS build-arm
RUN apt -y update && \
apt -y install wget curl && \
wget "https://github.com/pgaskin/kepubify/releases/latest/download/kepubify-linux-arm" -O /usr/bin/kepubify && \
@ -41,9 +41,8 @@ RUN apt -y update && \
apt -y autoremove && rm -rf /var/lib/apt/lists/*
FROM build-${TARGETARCH} AS runner
VOLUME /tmp
VOLUME /config
WORKDIR app
WORKDIR /app
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./

File diff suppressed because it is too large Load diff

View file

@ -3,14 +3,24 @@ package org.gotson.komga.domain.model
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonTypeInfo
import io.swagger.v3.oas.annotations.media.Schema
class SearchCondition {
@Schema(
name = "SearchConditionBook",
oneOf = [AnyOfBook::class, AllOfBook::class, LibraryId::class, ReadListId::class, SeriesId::class, Deleted::class, OneShot::class, Title::class, ReleaseDate::class, Tag::class, NumberSort::class, ReadStatus::class, MediaStatus::class, MediaProfile::class, Author::class, Poster::class],
)
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
sealed interface Book
@Schema(
name = "SearchConditionSeries",
oneOf = [AnyOfSeries::class, AllOfSeries::class, LibraryId::class, CollectionId::class, Deleted::class, Complete::class, OneShot::class, Title::class, TitleSort::class, ReleaseDate::class, Tag::class, SharingLabel::class, Publisher::class, Language::class, Genre::class, AgeRating::class, ReadStatus::class, SeriesStatus::class, Author::class],
)
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
sealed interface Series
@Schema(name = "SearchConditionAnyOfBook")
data class AnyOfBook(
@JsonProperty("anyOf")
val conditions: List<Book>,
@ -18,6 +28,7 @@ class SearchCondition {
constructor(vararg args: Book) : this(args.toList())
}
@Schema(name = "SearchConditionAllOfBook")
data class AllOfBook(
@JsonProperty("allOf")
val conditions: List<Book>,
@ -25,6 +36,7 @@ class SearchCondition {
constructor(vararg args: Book) : this(args.toList())
}
@Schema(name = "SearchConditionAnyOfSeries")
data class AnyOfSeries(
@JsonProperty("anyOf")
val conditions: List<Series>,
@ -32,6 +44,7 @@ class SearchCondition {
constructor(vararg args: Series) : this(args.toList())
}
@Schema(name = "SearchConditionAllOfSeries")
data class AllOfSeries(
@JsonProperty("allOf")
val conditions: List<Series>,
@ -39,118 +52,140 @@ class SearchCondition {
constructor(vararg args: Series) : this(args.toList())
}
@Schema(name = "SearchConditionLibraryId")
data class LibraryId(
@JsonProperty("libraryId")
val operator: SearchOperator.Equality<String>,
) : Book,
Series
@Schema(name = "SearchConditionCollectionId")
data class CollectionId(
@JsonProperty("collectionId")
val operator: SearchOperator.Equality<String>,
) : Series
@Schema(name = "SearchConditionReadListId")
data class ReadListId(
@JsonProperty("readListId")
val operator: SearchOperator.Equality<String>,
) : Book
@Schema(name = "SearchConditionSeriesId")
data class SeriesId(
@JsonProperty("seriesId")
val operator: SearchOperator.Equality<String>,
) : Book
@Schema(name = "SearchConditionDeleted")
data class Deleted(
@JsonProperty("deleted")
val operator: SearchOperator.Boolean,
) : Book,
Series
@Schema(name = "SearchConditionComplete")
data class Complete(
@JsonProperty("complete")
val operator: SearchOperator.Boolean,
) : Series
@Schema(name = "SearchConditionOneShot")
data class OneShot(
@JsonProperty("oneShot")
val operator: SearchOperator.Boolean,
) : Book,
Series
@Schema(name = "SearchConditionTitle")
data class Title(
@JsonProperty("title")
val operator: SearchOperator.StringOp,
) : Book,
Series
@Schema(name = "SearchConditionTitleSort")
data class TitleSort(
@JsonProperty("titleSort")
val operator: SearchOperator.StringOp,
) : Series
@Schema(name = "SearchConditionReleaseDate")
data class ReleaseDate(
@JsonProperty("releaseDate")
val operator: SearchOperator.Date,
) : Book,
Series
@Schema(name = "SearchConditionNumberSort")
data class NumberSort(
@JsonProperty("numberSort")
val operator: SearchOperator.Numeric<Float>,
) : Book
@Schema(name = "SearchConditionTag")
data class Tag(
@JsonProperty("tag")
val operator: SearchOperator.EqualityNullable<String>,
) : Book,
Series
@Schema(name = "SearchConditionSharingLabel")
data class SharingLabel(
@JsonProperty("sharingLabel")
val operator: SearchOperator.EqualityNullable<String>,
) : Series
@Schema(name = "SearchConditionPublisher")
data class Publisher(
@JsonProperty("publisher")
val operator: SearchOperator.Equality<String>,
) : Series
@Schema(name = "SearchConditionLanguage")
data class Language(
@JsonProperty("language")
val operator: SearchOperator.Equality<String>,
) : Series
@Schema(name = "SearchConditionGenre")
data class Genre(
@JsonProperty("genre")
val operator: SearchOperator.EqualityNullable<String>,
) : Series
@Schema(name = "SearchConditionAgeRating")
data class AgeRating(
@JsonProperty("ageRating")
val operator: SearchOperator.NumericNullable<Int>,
) : Series
@Schema(name = "SearchConditionReadStatus")
data class ReadStatus(
@JsonProperty("readStatus")
val operator: SearchOperator.Equality<org.gotson.komga.domain.model.ReadStatus>,
) : Book,
Series
@Schema(name = "SearchConditionMediaStatus")
data class MediaStatus(
@JsonProperty("mediaStatus")
val operator: SearchOperator.Equality<Media.Status>,
) : Book
@Schema(name = "SearchConditionSeriesStatus")
data class SeriesStatus(
@JsonProperty("seriesStatus")
val operator: SearchOperator.Equality<SeriesMetadata.Status>,
) : Series
@Schema(name = "SearchConditionMediaProfile")
data class MediaProfile(
@JsonProperty("mediaProfile")
val operator: SearchOperator.Equality<org.gotson.komga.domain.model.MediaProfile>,
) : Book
@Schema(name = "SearchConditionAuthor")
data class Author(
@JsonProperty("author")
val operator: SearchOperator.Equality<AuthorMatch>,
@ -163,6 +198,7 @@ class SearchCondition {
val role: String? = null,
)
@Schema(name = "SearchConditionPoster")
data class Poster(
@JsonProperty("poster")
val operator: SearchOperator.Equality<PosterMatch>,

View file

@ -2,10 +2,21 @@ package org.gotson.komga.domain.model
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.annotation.JsonTypeName
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping
import io.swagger.v3.oas.annotations.media.Schema
import java.time.Duration
import java.time.ZonedDateTime
class SearchOperator {
@Schema(
name = "SearchOperatorEquality",
discriminatorProperty = "operator",
oneOf = [ Is::class, IsNot::class],
discriminatorMapping = [
DiscriminatorMapping("is", Is::class),
DiscriminatorMapping("isNot", IsNot::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -13,6 +24,17 @@ class SearchOperator {
)
sealed interface Equality<T>
@Schema(
name = "SearchOperatorEqualityNullable",
discriminatorProperty = "operator",
oneOf = [ Is::class, IsNot::class, IsNullT::class, IsNotNullT::class],
discriminatorMapping = [
DiscriminatorMapping("is", Is::class),
DiscriminatorMapping("isNot", IsNot::class),
DiscriminatorMapping("isNull", IsNullT::class),
DiscriminatorMapping("isNotNull", IsNotNullT::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -20,6 +42,21 @@ class SearchOperator {
)
sealed interface EqualityNullable<T>
@Schema(
name = "SearchOperatorString",
discriminatorProperty = "operator",
oneOf = [BeginsWith::class, DoesNotBeginWith::class, Contains::class, DoesNotContain::class, EndsWith::class, DoesNotEndWith::class, Is::class, IsNot::class],
discriminatorMapping = [
DiscriminatorMapping("beginsWith", BeginsWith::class),
DiscriminatorMapping("doesNotBeginWith", DoesNotBeginWith::class),
DiscriminatorMapping("contains", Contains::class),
DiscriminatorMapping("doesNotContain", DoesNotContain::class),
DiscriminatorMapping("endsWith", EndsWith::class),
DiscriminatorMapping("doesNotEndWith", DoesNotEndWith::class),
DiscriminatorMapping("is", Is::class),
DiscriminatorMapping("isNot", IsNot::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -27,6 +64,17 @@ class SearchOperator {
)
sealed interface StringOp
@Schema(
name = "SearchOperatorNumericT",
discriminatorProperty = "operator",
oneOf = [GreaterThan::class, LessThan::class, Is::class, IsNot::class],
discriminatorMapping = [
DiscriminatorMapping("greaterThan", GreaterThan::class),
DiscriminatorMapping("lessThan", LessThan::class),
DiscriminatorMapping("is", Is::class),
DiscriminatorMapping("isNot", IsNot::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -34,6 +82,19 @@ class SearchOperator {
)
sealed interface Numeric<T>
@Schema(
name = "SearchOperatorNumericNullable",
discriminatorProperty = "operator",
oneOf = [GreaterThan::class, LessThan::class, IsNullT::class, IsNotNullT::class, Is::class, IsNot::class],
discriminatorMapping = [
DiscriminatorMapping("greaterThan", GreaterThan::class),
DiscriminatorMapping("lessThan", LessThan::class),
DiscriminatorMapping("isNull", IsNullT::class),
DiscriminatorMapping("isNotNull", IsNotNullT::class),
DiscriminatorMapping("is", Is::class),
DiscriminatorMapping("isNot", IsNot::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -41,6 +102,19 @@ class SearchOperator {
)
sealed interface NumericNullable<T>
@Schema(
name = "SearchOperatorDate",
discriminatorProperty = "operator",
oneOf = [Before::class, After::class, IsInTheLast::class, IsNotInTheLast::class, IsNull::class, IsNotNull::class],
discriminatorMapping = [
DiscriminatorMapping("before", Before::class),
DiscriminatorMapping("after", After::class),
DiscriminatorMapping("isInTheLast", IsInTheLast::class),
DiscriminatorMapping("isNotInTheLast", IsNotInTheLast::class),
DiscriminatorMapping("isNull", IsNull::class),
DiscriminatorMapping("isNotNull", IsNotNull::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -48,6 +122,15 @@ class SearchOperator {
)
sealed interface Date
@Schema(
name = "SearchOperatorBoolean",
discriminatorProperty = "operator",
oneOf = [IsTrue::class, IsFalse::class],
discriminatorMapping = [
DiscriminatorMapping("isTrue", IsTrue::class),
DiscriminatorMapping("isFalse", IsFalse::class),
],
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
@ -55,6 +138,7 @@ class SearchOperator {
)
sealed interface Boolean
@Schema(name = "SearchOperatorIs")
@JsonTypeName("is")
data class Is<T>(
val value: T,
@ -64,6 +148,7 @@ class SearchOperator {
Numeric<T>,
NumericNullable<T>
@Schema(name = "SearchOperatorIsNot")
@JsonTypeName("isNot")
data class IsNot<T>(
val value: T,
@ -73,80 +158,97 @@ class SearchOperator {
Numeric<T>,
NumericNullable<T>
@Schema(name = "SearchOperatorContains")
@JsonTypeName("contains")
data class Contains(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorDoesNotContain")
@JsonTypeName("doesNotContain")
data class DoesNotContain(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorBeginsWith")
@JsonTypeName("beginsWith")
data class BeginsWith(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorDoesNotBeginWith")
@JsonTypeName("doesNotBeginWith")
data class DoesNotBeginWith(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorEndsWith")
@JsonTypeName("endsWith")
data class EndsWith(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorDoesNotEndWith")
@JsonTypeName("doesNotEndWith")
data class DoesNotEndWith(
val value: String,
) : StringOp
@Schema(name = "SearchOperatorGreaterThan")
@JsonTypeName("greaterThan")
data class GreaterThan<T>(
val value: T,
) : Numeric<T>,
NumericNullable<T>
@Schema(name = "SearchOperatorLessThan")
@JsonTypeName("lessThan")
data class LessThan<T>(
val value: T,
) : Numeric<T>,
NumericNullable<T>
@Schema(name = "SearchOperatorBefore")
@JsonTypeName("before")
data class Before(
val dateTime: ZonedDateTime,
) : Date
@Schema(name = "SearchOperatorAfter")
@JsonTypeName("after")
data class After(
val dateTime: ZonedDateTime,
) : Date
@Schema(name = "SearchOperatorIsInTheLast")
@JsonTypeName("isInTheLast")
data class IsInTheLast(
val duration: Duration,
) : Date
@Schema(name = "SearchOperatorIsNotInTheLast")
@JsonTypeName("isNotInTheLast")
data class IsNotInTheLast(
val duration: Duration,
) : Date
@Schema(name = "SearchOperatorIsTrue")
@JsonTypeName("isTrue")
data object IsTrue : Boolean
@Schema(name = "SearchOperatorIsFalse")
@JsonTypeName("isFalse")
data object IsFalse : Boolean
@Schema(name = "SearchOperatorIsNull")
@JsonTypeName("isNull")
data object IsNull : Date
@Schema(name = "SearchOperatorIsNotNull")
@JsonTypeName("isNotNull")
data object IsNotNull : Date
@Schema(name = "SearchOperatorIsNullT")
@JsonTypeName("isNull")
class IsNullT<T> :
NumericNullable<T>,
@ -160,6 +262,7 @@ class SearchOperator {
override fun hashCode(): Int = javaClass.hashCode()
}
@Schema(name = "SearchOperatorIsNotNullT")
@JsonTypeName("isNotNull")
class IsNotNullT<T> :
NumericNullable<T>,

View file

@ -24,6 +24,14 @@ interface MediaRepository {
fun update(media: Media)
/**
* Performs a full copy of a Media, including MediaExtension, pages, and files.
*/
fun copy(
fromBookId: String,
toBookId: String,
)
fun delete(bookId: String)
fun delete(bookIds: Collection<String>)

View file

@ -21,6 +21,10 @@ interface ThumbnailBookRepository {
fun existsById(thumbnailId: String): Boolean
fun getLibraryIdOrNull(thumbnailId: String): String?
fun getSeriesIdOrNull(thumbnailId: String): String?
fun insert(thumbnail: ThumbnailBook)
fun update(thumbnail: ThumbnailBook)

View file

@ -146,7 +146,6 @@ class BookAnalyzer(
): Media {
book.path.epub { epub ->
val (resources, missingResources) = epubExtractor.getResources(epub).partition { it.fileSize != null }
val isFixedLayout = epubExtractor.isFixedLayout(epub)
val isKepub = epubExtractor.isKepub(epub, resources)
val errors = mutableListOf<String>()
@ -180,13 +179,15 @@ class BookAnalyzer(
val divinaPages =
try {
epubExtractor.getDivinaPages(epub, isFixedLayout, analyzeDimensions)
epubExtractor.getDivinaPages(epub, analyzeDimensions)
} catch (e: Exception) {
logger.error(e) { "Error while getting EPUB Divina pages" }
errors.add("ERR_1038")
emptyList()
}
val isFixedLayout = divinaPages.isNotEmpty() || epubExtractor.isFixedLayout(epub)
val positions =
try {
epubExtractor.computePositions(epub, book.path, resources, isFixedLayout, isKepub)
@ -212,7 +213,7 @@ class BookAnalyzer(
status = Media.Status.READY,
pages = divinaPages,
files = resources,
pageCount = epubExtractor.computePageCount(epub),
pageCount = if (divinaPages.isNotEmpty()) divinaPages.size else epubExtractor.computePageCount(epub),
epubDivinaCompatible = divinaPages.isNotEmpty(),
epubIsKepub = isKepub,
extension =
@ -265,27 +266,28 @@ class BookAnalyzer(
fun getPoster(book: BookWithMedia): TypedBytes? =
when (book.media.profile) {
MediaProfile.DIVINA ->
divinaExtractors[book.media.mediaType]
?.getEntryStream(
book.book.path,
book.media.pages
.first()
.fileName,
)?.let {
TypedBytes(
it,
book.media.pages
.first()
.mediaType,
)
}
MediaProfile.DIVINA -> divinaExtractors[book.media.mediaType]?.getPoster(book)
MediaProfile.PDF -> pdfExtractor.getPageContentAsImage(book.book.path, 1)
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path)
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path) ?: if (book.media.epubDivinaCompatible) divinaExtractors[MediaType.ZIP.type]?.getPoster(book) else null
null -> null
}
private fun DivinaExtractor.getPoster(book: BookWithMedia): TypedBytes =
this
.getEntryStream(
book.book.path,
book.media.pages
.first()
.fileName,
).let {
TypedBytes(
it,
book.media.pages
.first()
.mediaType,
)
}
@Throws(
MediaNotReadyException::class,
IndexOutOfBoundsException::class,

View file

@ -381,9 +381,7 @@ class LibraryContentLifecycle(
logger.info { "Match found, restore $match into $bookToAdd" }
transactionTemplate.executeWithoutResult {
// copy media
mediaRepository.findById(match.id).let { deleted ->
mediaRepository.update(deleted.copy(bookId = bookToAdd.id))
}
mediaRepository.copy(match.id, bookToAdd.id)
// copy generated and user uploaded thumbnails
thumbnailBookRepository.findAllByBookIdAndType(match.id, setOf(ThumbnailBook.Type.GENERATED, ThumbnailBook.Type.USER_UPLOADED)).forEach { deleted ->

View file

@ -1,6 +1,7 @@
package org.gotson.komga.infrastructure.jooq.main
import com.fasterxml.jackson.databind.ObjectMapper
import io.github.oshai.kotlinlogging.KotlinLogging
import org.gotson.komga.domain.model.BookPage
import org.gotson.komga.domain.model.Dimension
import org.gotson.komga.domain.model.Media
@ -26,6 +27,8 @@ import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
import java.time.ZoneId
private val logger = KotlinLogging.logger {}
@Component
class MediaDao(
dslRW: DSLContext,
@ -158,7 +161,14 @@ class MediaDao(
media.pageCount,
media.epubDivinaCompatible,
media.epubIsKepub,
media.extension?.let { if (it is ProxyExtension) null else it::class.qualifiedName },
media.extension?.let {
if (it is ProxyExtension) {
logger.error { "Found ProxyExtension while trying to insert Media: this is not expected and should be reported." }
null
} else {
it::class.qualifiedName
}
},
media.extension?.let { if (it is ProxyExtension) null else mapper.serializeJsonGz(it) },
)
}
@ -249,9 +259,13 @@ class MediaDao(
.set(m.EPUB_DIVINA_COMPATIBLE, media.epubDivinaCompatible)
.set(m.EPUB_IS_KEPUB, media.epubIsKepub)
.apply {
if (media.extension != null && media.extension !is ProxyExtension) {
set(m.EXTENSION_CLASS, media.extension::class.qualifiedName)
set(m.EXTENSION_VALUE_BLOB, mapper.serializeJsonGz(media.extension))
if (media.extension != null) {
if (media.extension !is ProxyExtension) {
set(m.EXTENSION_CLASS, media.extension::class.qualifiedName)
set(m.EXTENSION_VALUE_BLOB, mapper.serializeJsonGz(media.extension))
} else {
logger.error { "Found ProxyExtension while trying to update Media: this is not expected and should be reported." }
}
}
}.set(m.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z")))
.where(m.BOOK_ID.eq(media.bookId))
@ -271,6 +285,18 @@ class MediaDao(
dslRW.insertFiles(listOf(media))
}
@Transactional
override fun copy(
fromBookId: String,
toBookId: String,
) {
val source = findById(fromBookId)
val sourceExtension = findExtensionByIdOrNull(fromBookId)
val copy = source.copy(bookId = toBookId, extension = sourceExtension)
update(copy)
}
@Transactional
override fun delete(bookId: String) {
dslRW.deleteFrom(p).where(p.BOOK_ID.eq(bookId)).execute()

View file

@ -22,6 +22,7 @@ class ThumbnailBookDao(
) : SplitDslDaoBase(dslRW, dslRO),
ThumbnailBookRepository {
private val tb = Tables.THUMBNAIL_BOOK
private val b = Tables.BOOK
override fun findAllByBookId(bookId: String): Collection<ThumbnailBook> =
dslRO
@ -72,6 +73,24 @@ class ThumbnailBookDao(
override fun existsById(thumbnailId: String): Boolean = dslRO.fetchExists(tb, tb.ID.eq(thumbnailId))
override fun getLibraryIdOrNull(thumbnailId: String): String? =
dslRO
.select(b.LIBRARY_ID)
.from(tb)
.leftJoin(b)
.on(tb.BOOK_ID.eq(b.ID))
.where(tb.ID.eq(thumbnailId))
.fetchOne(b.LIBRARY_ID)
override fun getSeriesIdOrNull(thumbnailId: String): String? =
dslRO
.select(b.SERIES_ID)
.from(tb)
.leftJoin(b)
.on(tb.BOOK_ID.eq(b.ID))
.where(tb.ID.eq(thumbnailId))
.fetchOne(b.SERIES_ID)
override fun insert(thumbnail: ThumbnailBook) {
dslRW
.insertInto(tb)

View file

@ -18,6 +18,7 @@ import org.springframework.util.LinkedMultiValueMap
import org.springframework.web.client.RestClient
import org.springframework.web.client.toEntity
import org.springframework.web.server.ResponseStatusException
import org.springframework.web.util.DefaultUriBuilderFactory
import kotlin.time.Duration.Companion.minutes
import kotlin.time.toJavaDuration
@ -29,11 +30,15 @@ class KoboProxy(
private val komgaSyncTokenGenerator: KomgaSyncTokenGenerator,
private val komgaSettingsProvider: KomgaSettingsProvider,
) {
private val koboApiClient =
private val koboApiClient: RestClient =
RestClient
.builder()
.baseUrl("https://storeapi.kobo.com")
.requestFactory(
.uriBuilderFactory(
DefaultUriBuilderFactory("https://storeapi.kobo.com")
.apply {
this.encodingMode = DefaultUriBuilderFactory.EncodingMode.NONE
},
).requestFactory(
ClientHttpRequestFactoryBuilder.reactor().build(
ClientHttpRequestFactorySettings
.defaults()
@ -42,7 +47,7 @@ class KoboProxy(
),
).build()
private val pathRegex = """\/kobo\/[-\w]*(.*)""".toRegex()
private val pathRegex = """/kobo/[-\w]*(.*)""".toRegex()
private val headersOutInclude =
setOf(
@ -50,6 +55,7 @@ class KoboProxy(
HttpHeaders.USER_AGENT,
HttpHeaders.ACCEPT,
HttpHeaders.ACCEPT_LANGUAGE,
HttpHeaders.CONTENT_TYPE,
)
private val headersOutExclude =
@ -68,7 +74,7 @@ class KoboProxy(
* raw Kobo sync token returned, and added to the response headers.
*/
fun proxyCurrentRequest(
body: Any? = null,
body: ByteArray? = null,
includeSyncToken: Boolean = false,
): ResponseEntity<JsonNode> {
if (!komgaSettingsProvider.koboProxy) throw IllegalStateException("kobo proxying is disabled")
@ -110,6 +116,7 @@ class KoboProxy(
}.apply { if (body != null) body(body) }
.retrieve()
.onStatus(HttpStatusCode::isError) { _, response ->
logger.debug { "Kobo response: ${response.statusCode}: ${response.body.bufferedReader().use { it.readText() }}" }
throw ResponseStatusException(response.statusCode, response.statusText)
}.toEntity<JsonNode>()

View file

@ -28,7 +28,6 @@ class RarExtractor(
): List<MediaContainerEntry> =
Archive(path.toFile()).use { rar ->
if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported", "ERR_1002")
if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported", "ERR_1003")
if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported", "ERR_1004")
rar.fileHeaders
.filter { !it.isDirectory }

View file

@ -46,7 +46,7 @@ class EpubExtractor(
fun isEpub(path: Path): Boolean =
try {
getEntryStream(path, "mimetype").decodeToString().trim() == "application/epub+zip"
} catch (e: Exception) {
} catch (_: Exception) {
false
}
@ -67,7 +67,7 @@ class EpubExtractor(
?: // try id="cover-image"
manifest.values.firstOrNull { it.id == "cover-image" }
if (coverManifestItem != null) {
val href = coverManifestItem.href
val href = URLDecoder.decode(coverManifestItem.href, Charsets.UTF_8)
val mediaType = coverManifestItem.mediaType
val coverPath = normalizeHref(opfDir, href)
zip.getEntryBytes(coverPath)?.let { coverBytes ->
@ -114,14 +114,8 @@ class EpubExtractor(
fun getDivinaPages(
epub: EpubPackage,
isFixedLayout: Boolean,
analyzeDimensions: Boolean,
): List<BookPage> {
if (!isFixedLayout) {
logger.info { "Epub Divina detection failed: book is not fixed layout" }
return emptyList()
}
val pageCount =
run {
val spine =
@ -139,24 +133,31 @@ class EpubExtractor(
epub.opfDoc
.select("*|spine > *|itemref")
.map { it.attr("idref") }
.mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } }
.map { pagePath ->
val doc = epub.zip.getEntryInputStream(pagePath)?.use { Jsoup.parse(it, null, "") } ?: return@map emptyList()
.mapNotNull { idref ->
val manifestItem = epub.manifest[idref] ?: return@mapNotNull null
normalizeHref(epub.opfDir, manifestItem.href) to manifestItem.mediaType
}.map { (pagePath, mediaType) ->
if (mediaType.startsWith("image", true)) {
// image in spine
listOf(Path(pagePath).normalize().invariantSeparatorsPathString)
} else {
val doc = epub.zip.getEntryInputStream(pagePath)?.use { Jsoup.parse(it, null, "") } ?: return@map emptyList()
// if a page has text over the threshold then the book is not divina compatible
if (doc.body().text().length > letterCountThreshold) return emptyList()
// if a page has text over the threshold then the book is not divina compatible
if (doc.body().text().length > letterCountThreshold) return emptyList()
val img =
doc
.getElementsByTag("img")
.map { it.attr("src") } // get the src, which can be a relative path
val img =
doc
.getElementsByTag("img")
.map { it.attr("src") } // get the src, which can be a relative path
val svg =
doc
.select("svg > image[xlink:href]")
.map { it.attr("xlink:href") } // get the source, which can be a relative path
val svg =
doc
.select("svg > image[xlink:href]")
.map { it.attr("xlink:href") } // get the source, which can be a relative path
(img + svg).map { (Path(pagePath).parent ?: Path("")).resolve(it).normalize().invariantSeparatorsPathString } // resolve it against the page folder
(img + svg).map { (Path(pagePath).parent ?: Path("")).resolve(it).normalize().invariantSeparatorsPathString } // resolve it against the page folder
}
}
if (pagesWithImages.size != pageCount) {
@ -164,7 +165,7 @@ class EpubExtractor(
return emptyList()
}
// Only keep unique image path for each page. KCC sometimes generates HTML pages with 5 times the same image.
val imagesPath = pagesWithImages.map { it.distinct() }.flatten()
val imagesPath = pagesWithImages.flatMap { it.distinct() }
if (imagesPath.size != pageCount) {
logger.info { "Epub Divina detection failed: book has ${imagesPath.size} detected images, but $pageCount total pages" }
return emptyList()
@ -259,7 +260,7 @@ class EpubExtractor(
val positions = computePositionsFromKoboSpan(readingOrder) { filename -> getZipEntryBytes(kepub, filename).decodeToString() }
kepub.deleteIfExists()
positions
} catch (e: Exception) {
} catch (_: Exception) {
logger.warn { "Could not convert to Kepub to compute positions: $path" }
emptyMap()
}
@ -336,7 +337,8 @@ class EpubExtractor(
fun getToc(epub: EpubPackage): List<EpubTocEntry> {
// Epub 3
epub.getNavResource()?.let { return processNav(it, Epub3Nav.TOC) }
epub.getNavResource()?.let { processNav(it, Epub3Nav.TOC) }?.let { if (it.isNotEmpty()) return it }
// Epub 2
epub.getNcxResource()?.let { return processNcx(it, Epub2Nav.TOC) }
return emptyList()
@ -344,7 +346,8 @@ class EpubExtractor(
fun getPageList(epub: EpubPackage): List<EpubTocEntry> {
// Epub 3
epub.getNavResource()?.let { return processNav(it, Epub3Nav.PAGELIST) }
epub.getNavResource()?.let { processNav(it, Epub3Nav.PAGELIST) }?.let { if (it.isNotEmpty()) return it }
// Epub 2
epub.getNcxResource()?.let { return processNcx(it, Epub2Nav.PAGELIST) }
return emptyList()
@ -352,7 +355,7 @@ class EpubExtractor(
fun getLandmarks(epub: EpubPackage): List<EpubTocEntry> {
// Epub 3
epub.getNavResource()?.let { return processNav(it, Epub3Nav.LANDMARKS) }
epub.getNavResource()?.let { processNav(it, Epub3Nav.LANDMARKS) }?.let { if (it.isNotEmpty()) return it }
// Epub 2
return processOpfGuide(epub.opfDoc, epub.opfDir)

View file

@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.EpubTocEntry
import org.gotson.komga.infrastructure.util.getEntryBytes
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import org.jsoup.parser.Parser
import java.net.URLDecoder
import java.nio.file.Path
import kotlin.io.path.Path
@ -20,7 +21,7 @@ fun processNav(
document: ResourceContent,
navElement: Epub3Nav,
): List<EpubTocEntry> {
val doc = Jsoup.parse(document.content)
val doc = Jsoup.parse(document.content, "", Parser.xmlParser())
val nav =
doc
.select("nav")

View file

@ -0,0 +1,44 @@
package org.gotson.komga.infrastructure.openapi
import org.springdoc.core.customizers.OpenApiCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
/**
* The generated schema for sealed classes is somehow wrong.
* This customizer will correct the issues.
*/
@Configuration
@Order(Ordered.LOWEST_PRECEDENCE)
class InheritanceFlattenerConfiguration {
private val schemaPrefix = listOf("SearchOperator", "SearchCondition")
@Bean
fun flattenInheritedSchemasCustomizer(): OpenApiCustomizer =
OpenApiCustomizer { openApi ->
openApi.components
?.schemas
?.values
?.filter { schema -> schemaPrefix.any { prefix -> schema.name.startsWith(prefix, false) } }
?.forEach { schema ->
// Swagger models inheritance as an allOf list with exactly two items:
// 1. The $ref to the parent interface
// 2. An inline schema containing the child's actual properties
if (schema.allOf != null) {
val refSchema = schema.allOf.filter { it.`$ref` != null }
val inlineSchema = schema.allOf.find { it.properties != null }
// If both are found, we know this is an inherited schema wrapper
if (refSchema.isNotEmpty() && inlineSchema != null) {
// Move the properties up to the root schema
schema.properties = inlineSchema.properties
// Delete the allOf array entirely
schema.allOf = null
}
}
}
}
}

View file

@ -4,6 +4,7 @@ import org.gotson.komga.domain.model.Book
import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.domain.persistence.BookRepository
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
import org.gotson.komga.domain.persistence.ThumbnailBookRepository
import org.gotson.komga.interfaces.api.rest.dto.BookDto
import org.gotson.komga.interfaces.api.rest.dto.SeriesDto
import org.springframework.http.HttpStatus
@ -14,6 +15,7 @@ import org.springframework.web.server.ResponseStatusException
class ContentRestrictionChecker(
private val seriesMetadataRepository: SeriesMetadataRepository,
private val bookRepository: BookRepository,
private val thumbnailBookRepository: ThumbnailBookRepository,
) {
/**
* Convenience function to check for content restriction.
@ -84,4 +86,26 @@ class ContentRestrictionChecker(
if (!komgaUser.canAccessLibrary(series.libraryId)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
if (!komgaUser.isContentAllowed(series.metadata.ageRating, series.metadata.sharingLabels)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
}
/**
* Convenience function to check for content restriction.
*
* @throws[ResponseStatusException] if the user cannot access the content
*/
fun checkContentRestrictionBookThumbnail(
komgaUser: KomgaUser,
thumbnailId: String,
) {
if (!komgaUser.canAccessAllLibraries()) {
thumbnailBookRepository.getLibraryIdOrNull(thumbnailId)?.let {
if (!komgaUser.canAccessLibrary(it)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
if (komgaUser.restrictions.isRestricted)
thumbnailBookRepository.getSeriesIdOrNull(thumbnailId)?.let { seriesId ->
seriesMetadataRepository.findById(seriesId).let {
if (!komgaUser.isContentAllowed(it.ageRating, it.sharingLabels)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
}
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
}

View file

@ -92,7 +92,7 @@ class OpdsGenerator(
links =
listOf(
WPLinkDto(rel = "help", href = "https://komga.org"),
WPLinkDto(rel = "logo", href = ServletUriComponentsBuilder.fromCurrentContextPath().path("android-chrome-512x512.png").toUriString()),
WPLinkDto(rel = "logo", href = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("android-chrome-512x512.png").toUriString()),
),
authentication =
listOf(

View file

@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.kobo
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.treeToValue
import com.github.benmanes.caffeine.cache.Caffeine
import io.github.oshai.kotlinlogging.KotlinLogging
@ -174,6 +175,7 @@ class KoboController(
private val imageConverter: ImageConverter,
private val mediaRepository: MediaRepository,
private val contentRestrictionChecker: ContentRestrictionChecker,
private val objectMapper: ObjectMapper,
) {
private val cachedKepub =
Caffeine
@ -194,6 +196,7 @@ class KoboController(
try {
koboProxy.proxyCurrentRequest().body?.get("Resources")
} 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" }
null
} ?: koboProxy.nativeKoboResources
@ -229,14 +232,16 @@ class KoboController(
*/
@PostMapping("v1/auth/device")
fun authDevice(
@RequestBody body: JsonNode,
@RequestBody rawBody: ByteArray,
): Any {
try {
return koboProxy.proxyCurrentRequest(body)
} catch (e: Exception) {
return koboProxy.proxyCurrentRequest(rawBody)
} catch (_: Exception) {
logger.warn { "Failed to get response from Kobo /v1/auth/device, fallback to noproxy" }
}
val body = objectMapper.readTree(rawBody)
/**
* Komga does not use the /v1/auth/device API call for authentication/authorization.
* Return dummy data to keep the device happy.
@ -395,7 +400,7 @@ class KoboController(
addAll(
// 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 ->
readProgress[book.bookId]?.let { it ->
readProgress[book.bookId]?.let {
ChangedReadingStateDto(
WrappedReadingStateDto(
it.toDto(),
@ -511,13 +516,17 @@ class KoboController(
*/
@GetMapping("/v1/library/{bookId}/metadata")
fun getBookMetadata(
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable authToken: String,
@PathVariable bookId: String,
): ResponseEntity<*> =
if (!bookRepository.existsById(bookId) && koboProxy.isEnabled())
if (!bookRepository.existsById(bookId) && koboProxy.isEnabled()) {
koboProxy.proxyCurrentRequest()
else
} else {
contentRestrictionChecker.checkContentRestriction(principal.user, bookId)
ResponseEntity.ok(koboDtoRepository.findBookMetadataByIds(listOf(bookId)).map { it.withDownloadUrls(getDownloadUrlBuilder(authToken)) })
}
/**
* @return an array of [ReadingStateDto]
@ -534,6 +543,8 @@ class KoboController(
else
throw ResponseStatusException(HttpStatus.NOT_FOUND)
contentRestrictionChecker.checkContentRestriction(principal.user, book)
val response = readProgressRepository.findByBookIdAndUserIdOrNull(bookId, principal.user.id)?.toDto() ?: getEmptyReadProgressForBook(book)
return ResponseEntity.ok(listOf(response))
}
@ -545,16 +556,20 @@ class KoboController(
fun updateState(
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable bookId: String,
@RequestBody body: ReadingStateStateUpdateDto,
@RequestBody rawBody: ByteArray,
@RequestHeader(name = X_KOBO_DEVICEID, required = false) koboDeviceId: String = "unknown",
): ResponseEntity<*> {
val body = objectMapper.readValue<ReadingStateStateUpdateDto>(rawBody)
val book =
bookRepository.findByIdOrNull(bookId)
?: if (koboProxy.isEnabled())
return koboProxy.proxyCurrentRequest(body)
return koboProxy.proxyCurrentRequest(rawBody)
else
throw ResponseStatusException(HttpStatus.NOT_FOUND)
contentRestrictionChecker.checkContentRestriction(principal.user, book)
val koboUpdate = body.readingStates.firstOrNull() ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST)
if (koboUpdate.currentBookmark.location == null || koboUpdate.currentBookmark.contentSourceProgressPercent == null) throw ResponseStatusException(HttpStatus.BAD_REQUEST)
@ -718,6 +733,8 @@ class KoboController(
.location(UriComponentsBuilder.fromUriString(koboProxy.imageHostUrl).buildAndExpand(thumbnailId, width, height).toUri())
.build()
} else {
contentRestrictionChecker.checkContentRestrictionBookThumbnail(principal.user, thumbnailId)
val poster = bookLifecycle.getThumbnailBytesByThumbnailId(thumbnailId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
val posterBytes =
if (poster.mediaType != ImageType.JPEG.mediaType)
@ -732,7 +749,7 @@ class KoboController(
method = [RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PATCH],
)
fun catchAll(
@RequestBody body: Any?,
@RequestBody body: ByteArray?,
): ResponseEntity<JsonNode> =
if (koboProxy.isEnabled())
koboProxy.proxyCurrentRequest(body)

View file

@ -14,6 +14,7 @@ import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.gotson.komga.interfaces.api.kosync.dto.DocumentProgressDto
import org.gotson.komga.interfaces.api.kosync.dto.UserAuthenticationDto
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
@ -29,7 +30,7 @@ import java.time.ZonedDateTime
private val logger = KotlinLogging.logger {}
@RestController
@RequestMapping("/koreader", produces = ["application/vnd.koreader.v1+json"])
@RequestMapping("/koreader", produces = [MediaType.APPLICATION_JSON_VALUE, "application/vnd.koreader.v1+json"])
class KoreaderSyncController(
private val bookRepository: BookRepository,
private val mediaRepository: MediaRepository,

View file

@ -435,7 +435,7 @@ class Opds2Controller(
PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("lastModified"))),
).map { it.toWPLinkDto() }
val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/books/latest")
val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/series/latest")
return FeedDto(
metadata =

View file

@ -268,7 +268,7 @@ class ReadListController(
}
@Operation(summary = "Match ComicRack list", tags = [OpenApiConfiguration.TagNames.COMICRACK])
@PostMapping("match/comicrack")
@PostMapping("match/comicrack", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
@PreAuthorize("hasRole('ADMIN')")
fun matchComicRackList(
@RequestParam("file") file: MultipartFile,

View file

@ -112,10 +112,12 @@ class UserController(
restrictions =
ContentRestrictions(
ageRestriction =
if (ageRestriction == null || ageRestriction.restriction == AllowExcludeDto.NONE)
null
else
AgeRestriction(ageRestriction.age, ageRestriction.restriction.toDomain()),
ageRestriction.let {
if (it == null || it.restriction == AllowExcludeDto.NONE)
null
else
AgeRestriction(it.age, it.restriction.toDomain())
},
labelsAllow = labelsAllow ?: emptySet(),
labelsExclude = labelsExclude ?: emptySet(),
),

View file

@ -1,10 +1,12 @@
package org.gotson.komga.interfaces.api.rest.dto
import com.fasterxml.jackson.annotation.JsonInclude
import org.gotson.komga.domain.model.AgeRestriction
import org.gotson.komga.domain.model.AllowExclude
import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.infrastructure.security.KomgaPrincipal
@JsonInclude(JsonInclude.Include.NON_NULL)
data class UserDto(
val id: String,
val email: String,

View file

@ -55,6 +55,19 @@ class SseController(
return emitter
}
@Scheduled(fixedRate = 15_000)
fun heartbeat() {
if (emitters.isNotEmpty())
synchronized(emitters) {
emitters.forEach { (emitter, _) ->
try {
emitter.send(SseEmitter.event().comment("heartbeat"))
} catch (_: IOException) {
}
}
}
}
@Scheduled(fixedRate = 10_000)
fun taskCount() {
if (emitters.isNotEmpty()) {

View file

@ -59,14 +59,21 @@ class BookAnalyzerTest(
assertThat(media.pages).hasSize(3)
}
@ParameterizedTest
@ValueSource(
strings = [
"rar4-solid.rar", "rar4-encrypted.rar",
],
)
fun `given rar4 solid or encrypted archive when analyzing then media status is UNSUPPORTED`(fileName: String) {
val file = ClassPathResource("archives/$fileName")
@Test
fun `given rar4 solid archive when analyzing then media status is READY`() {
val file = ClassPathResource("archives/rar4-solid.rar")
val book = Book("book", file.url, LocalDateTime.now())
val media = bookAnalyzer.analyze(book, false)
assertThat(media.mediaType).isEqualTo("application/x-rar-compressed; version=4")
assertThat(media.status).isEqualTo(Media.Status.READY)
assertThat(media.pages).hasSize(3)
}
@Test
fun `given rar4 encrypted archive when analyzing then media status is UNSUPPORTED`() {
val file = ClassPathResource("archives/rar4-encrypted.rar")
val book = Book("book", file.url, LocalDateTime.now())
val media = bookAnalyzer.analyze(book, false)
@ -144,7 +151,6 @@ class BookAnalyzerTest(
assertThat(media.mediaType).isEqualTo("application/epub+zip")
assertThat(media.status).isEqualTo(Media.Status.READY)
assertThat(media.pages).hasSize(0)
}
}
@ -230,7 +236,7 @@ class BookAnalyzerTest(
val file = ClassPathResource("epub/The Incomplete Theft - Ralph Burke.epub")
val book = Book("book", file.url, LocalDateTime.now())
every { epubExtractor.getDivinaPages(any(), any(), any()) } throws Exception("mock exception")
every { epubExtractor.getDivinaPages(any(), any()) } throws Exception("mock exception")
val media = bookAnalyzer.analyze(book, false)

View file

@ -3,6 +3,7 @@ package org.gotson.komga.infrastructure.mediacontainer.epub
import org.assertj.core.api.Assertions.assertThat
import org.gotson.komga.domain.model.EpubTocEntry
import org.jsoup.Jsoup
import org.jsoup.parser.Parser
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import org.springframework.core.io.ClassPathResource
@ -15,7 +16,7 @@ class OpfTest {
// given
val opfResource = ClassPathResource("epub/clash.opf")
val opfString = opfResource.inputStream.readAllBytes().decodeToString()
val opfDoc = Jsoup.parse(opfString)
val opfDoc = Jsoup.parse(opfString, "", Parser.xmlParser())
// when
val opfLandmarks = processOpfGuide(opfDoc, if (prefix.isBlank()) null else Path.of(prefix))

View file

@ -7,9 +7,13 @@ import org.gotson.komga.domain.service.KomgaUserLifecycle
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.test.web.servlet.post
@ -68,4 +72,17 @@ class KoreaderSyncControllerTest(
jsonPath("authorized") { value("OK") }
}
}
@ParameterizedTest
@ValueSource(strings = [MediaType.APPLICATION_JSON_VALUE, "application/vnd.koreader.v1+json"])
fun `given accept header when calling API user then returns OK`(acceptHeader: String) {
mockMvc
.get("/koreader/users/auth") {
header("x-auth-user", apiKey)
header(HttpHeaders.ACCEPT, acceptHeader)
}.andExpect {
status { isOk() }
jsonPath("authorized") { value("OK") }
}
}
}

View file

@ -113,7 +113,7 @@ class UserControllerTest(
jsonPath("$.sharedLibrariesId") { doesNotExist() }
jsonPath("$.labelsAllow") { isEmpty() }
jsonPath("$.labelsExclude") { isEmpty() }
jsonPath("$.ageRestriction") { isEmpty() }
jsonPath("$.ageRestriction") { doesNotExist() }
}
}
}