Compare commits

..

173 Commits

Author SHA1 Message Date
fallenbagel
e5421a1003 refactor(i18n): merge weblate/develop into origin/develop 2024-03-31 16:42:54 +05:00
Fallenbagel
0900a95532 fix: nullable type for jellyfinMediaId(4k) (#702)
The jellyfinMediaId(4k) properties were inferred as string | undefined, causing them to be set to
undefined when assigning null. This prevented the media from being saved correctly to the SQLite
database, as it doesn't accept undefined values. This resolves the availabilitySync job issue where
the "play on" button wasn't being removed for all media server types.

fix #668
2024-03-31 16:26:09 +05:00
Fallenbagel
0c86684bc2 refactor(i18n): change the user-facing identity of the application in i18n (#703) 2024-03-31 16:25:45 +05:00
Danish Humair
010df62776 feat: check if first jellyfin user is admin (#635)
* feat: merge check if first jellyfin user is admin

re #610

* refactor(i18n): extract admin error message into en locale

---------

Co-authored-by: fallenbagel <98979876+Fallenbagel@users.noreply.github.com>
2024-03-30 05:53:14 +05:00
Fallenbagel
530be4272c fix(jellyfinscanner): conditionally assign the jellyfinMediaId and jellyfinMediaId4k (#686)
Previously `jellyfinMediaId4k` was being assigned even if 4k server was not setup or even if 4k
content were not present. This fixes it by conditionally assigning the jellyfinMediaId and
JellyfinMediaId4k

fix #681
2024-03-14 03:11:53 +05:00
Fallenbagel
c2e87714b4 fix(embyauth): remove the accidentally added mediaServerType change code from another PR (#684)
Accidentally added the mediaServerType change code from another feature branch/PR during the auth
logic refactor that broke emby logins.
2024-03-14 01:08:09 +05:00
Gauvino
eee9a025d2 fix: typos on readme (#655)
* Fix typo

* Apply suggestions

* Apply suggestions

---------

Co-authored-by: Fallenbagel <98979876+Fallenbagel@users.noreply.github.com>
2024-02-23 12:57:57 +05:00
allcontributors[bot]
aed011a557 docs: add trackmastersteve as a contributor for doc (#665)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-02-23 09:39:53 +05:00
Stephen Harris
ea47dd3571 Fixed a typo (#654)
Just a simple typo fix.
2024-02-23 09:38:45 +05:00
Fallenbagel
4c9013729e refactor: jellyfin authentication and add gravatar for missing avatars of jellyfin users (#664)
* refactor: jellyfin authentication

This refactor standardizes the authentication approach in Jellyfin to mirror the method employed in
Plex authentication for consistency

* feat: use gravatar for jellyfin users' with missing jellyfin avatars
2024-02-23 09:38:18 +05:00
Fallenbagel
3eb1bb3d8f feat(job): media availability support for jellyfin/emby (#522)
* feat(job): media availability support for jellyfin/emby

This refactors the media availability job to support jellyfin/emby for media removal automatically.
Needs further testing on 4k items (as I have not yet tested with 4k), however, non-4k items work as
intended.

fix #406, fix #193, fix #516, fix #362, fix #84

* fix(availabilitysync): use the correct 4k jellyfinMediaId

* fix: season mapping for plex

Fixes a bug introduced with this PR where media availability sync job removed the seasons from all
series even when those seasons existed
2024-02-23 07:42:59 +05:00
InvalidArgumentException
db84f6529a fix(jellyfin.ts): process virtual seasons if they have non virtual episodes (#639)
All seasons are processed now, but those without any episodes are filtered out again as unavailable.
This fixes in issue where jellyfin reports all seasons as virtual
2024-02-01 16:10:06 +05:00
Fallenbagel
4f81788386 Merge pull request #640 from Fallenbagel/all-contributors/add-Danish-H
docs: add Danish-H as a contributor for code
2024-01-29 00:54:02 +05:00
allcontributors[bot]
72d3f9b908 docs: update .all-contributorsrc [skip ci] 2024-01-28 19:53:51 +00:00
allcontributors[bot]
333ffed7f0 docs: update README.md [skip ci] 2024-01-28 19:53:50 +00:00
Fallenbagel
8641a26771 Merge pull request #636 from Danish-H/feature-letterboxd-links
feat: added Letterboxd links for the external link blocks for movies
2024-01-29 00:53:29 +05:00
Fallenbagel
7329524868 Merge pull request #638 from Fallenbagel/all-contributors/add-aleksasiriski
docs: add aleksasiriski as a contributor for infra
2024-01-28 01:10:56 +05:00
allcontributors[bot]
908dcb487a docs: update .all-contributorsrc [skip ci] 2024-01-27 20:10:44 +00:00
allcontributors[bot]
d486d58d3d docs: update README.md [skip ci] 2024-01-27 20:10:43 +00:00
Fallenbagel
d8b08f4c6b Merge pull request #637 from aleksasiriski/patch-1
ci(preview): added arm support for preview tags
2024-01-28 00:50:23 +05:00
Aleksa Siriški
a48a337e0f ci(preview): added arm support for preview tags 2024-01-27 16:58:35 +01:00
Danish Humair
981f5e679c feat: added Letterboxd links for the external link blocks for movies 2024-01-27 03:25:03 +05:00
Fallenbagel
7af193b8f6 docs: fix weblate link 2024-01-13 22:05:03 +05:00
Fallenbagel
6040e16645 update discord badge 2024-01-04 02:02:16 +05:00
Fallenbagel
3877301fc8 add translation percentage badge 2024-01-04 02:00:49 +05:00
Fallenbagel
092a1458a4 move weblate details to contributing.md 2024-01-03 14:25:23 +05:00
Fallenbagel
1c68111b12 update weblate link 2024-01-03 14:24:45 +05:00
Fallenbagel
0e777ddb1e Merge pull request #612 from Fallenbagel/feat-readme-weblate
Add more badges and weblate status
2024-01-03 14:20:29 +05:00
Fallenbagel
52c689b080 Merge pull request #613 from Fallenbagel/all-contributors/add-xeruf
docs: add xeruf as a contributor for doc
2024-01-03 14:12:32 +05:00
allcontributors[bot]
1a11f085ba docs: update .all-contributorsrc [skip ci] 2024-01-03 09:12:19 +00:00
allcontributors[bot]
c0234582a6 docs: update README.md [skip ci] 2024-01-03 09:12:18 +00:00
Fallenbagel
fd958d6347 Merge pull request #611 from xeruf/patch-1
Link related projects in README.md
2024-01-03 14:10:17 +05:00
Fallenbagel
6586db52dc Add more badges and weblate status 2024-01-03 14:04:17 +05:00
Janek
a41cb8b004 Link related projects in README.md 2024-01-03 07:39:48 +01:00
Fallenbagel
de66222e7a Merge pull request #590 from Fallenbagel/all-contributors/add-mdll23
docs: add mdll23 as a contributor for translation
2023-12-03 21:04:28 +05:00
allcontributors[bot]
eb790cb466 docs: update .all-contributorsrc [skip ci] 2023-12-03 16:03:26 +00:00
allcontributors[bot]
0680931332 docs: update README.md [skip ci] 2023-12-03 16:03:26 +00:00
Fallenbagel
ff2821471e Merge pull request #589 from mdll23/develop
fix: translation de.json
2023-12-03 21:02:59 +05:00
mdll23
e032c02f5f fix: fix german translation for "components.Discover.FilterSlideover.tmdbuservotecount" 2023-12-03 15:13:19 +01:00
Fallenbagel
f8c4def229 Merge pull request #565 from notquitenothing/custom-jellyfin-password-reset
feat: Custom jellyfin password reset setting
2023-11-30 14:08:20 +05:00
fallenbagel
a0415e7b6b Merge branch 'develop' into custom-jellyfin-password-reset 2023-11-30 09:26:14 +05:00
fallenbagel
b5f672785a docs: reverted two unrelated files to its develop branch state 2023-11-30 09:25:34 +05:00
Fallenbagel
770d788fd7 Merge pull request #577 from Fallenbagel/fix-set-defaultValue-seasonFoldersInSonarr
fix: disable seasonfolder option in sonarr for jellyfin/Emby users
2023-11-30 09:04:46 +05:00
Fallenbagel
c58261c841 Merge pull request #578 from Fallenbagel/refactor-jellyfin-scan-job
refactor: jellyfin scan jobs moved from server/jobs to server/libs/scanners
2023-11-27 15:05:02 +05:00
fallenbagel
ccfcdea1f6 refactor: clean out commented code 2023-11-27 14:11:10 +05:00
fallenbagel
8ec8f2ac57 fix: disable seasonfolder option in sonarr for jellyfin/Emby users
This disables seasonfolder option in sonarr for jellyfin/emby users as physical seasonFolders are
necessary as virtualFolders are ignored since #126

fix #575
2023-11-27 13:58:46 +05:00
fallenbagel
91f97f96ab refactor: jellyfin scan jobs moved from server/jobs to server/libs/scanners 2023-11-27 11:09:45 +05:00
Fallenbagel
f4051a1e5d Merge pull request #572 from Fallenbagel/fix-filterSlideOver-datepicker
fix: correct width issue in datepicker of filterSliderOver
2023-11-19 18:47:49 +05:00
fallenbagel
f564cddff4 fix: correct width issue in datepicker of filterSliderOver
This commit addresses a rendering issue with the date picker component.
The problem was traced back to a misconfiguration in the tailwindcss settings, resulting in an
incorrect width for the popup.

fix #415
2023-11-19 18:08:06 +05:00
Fallenbagel
cfcce6acf0 Merge pull request #571 from Fallenbagel/fix-local-watchlist-page-item-removal
fix: ensure watchlist updates are immediately reflected
2023-11-19 16:47:45 +05:00
fallenbagel
b85d7f37b9 fix: ensure watchlist updates are immediately reflected
This fix addresses an issue on the Watchlist page where changes to the watchlist were not
immediately reflected. Previously, after removing an item from the watchlist, the update
required a full page reload or revalidating upon focusing the window or tab. With this fix,
the watchlist now correctly mutates and updates in real-time, providing a seamless user
experience.
2023-11-19 16:33:02 +05:00
Fallenbagel
97396c2f57 Merge pull request #568 from Fallenbagel/fix-local-watchlist-page-item-removal
fix(watchlist): added missing prop for watchlist item removal button in watchlist page
2023-11-18 06:29:25 +05:00
fallenbagel
a0ec992028 fix(watchlist): added missing prop for watchlist item removal button in watchlist page
This fix resolves a Watchlist page bug where the isAddedToWatchlist prop was missing.
Without this prop, the removal button for watchlist items was absent. In this fix, the
isAddedToWatchlist prop is re-added and set to true, allowing users to remove items from
their local watchlist directly on the Watchlist page.
2023-11-18 06:13:27 +05:00
Derek Paschal
0dfe050ba1 Fixing code formatting, prettier 2023-11-15 06:59:02 -06:00
Derek Paschal
13dd3cad54 Making the new setting optional 2023-11-14 08:51:29 -06:00
Derek Paschal
ce9802d5d4 Adding Jellyfin Setting for Custom "Forgot Password" URL
Adding Jellyfin Setting for Custom "Forgot Password" URL.  Useful in cases where you are using a custom authentication provider such as the LDAP plugin, Authelia, lldap, or any other external auth scheme with its own password reset page.
2023-11-14 08:20:28 -06:00
Fallenbagel
4005397f3d Merge pull request #564 from Fallenbagel/all-contributors/add-athphane
docs: add athphane as a contributor for doc
2023-11-11 14:43:44 +05:00
allcontributors[bot]
a67e4dbb80 docs: update .all-contributorsrc [skip ci] 2023-11-11 09:43:19 +00:00
allcontributors[bot]
cf5cf3f9ca docs: update README.md [skip ci] 2023-11-11 09:43:18 +00:00
Fallenbagel
8ae4391f37 Merge pull request #563 from athphane/update-github-templates
update .github folder templates
2023-11-11 14:41:41 +05:00
Athfan Khaleel
bfd77e271a update .github folder templates 2023-11-11 14:37:34 +05:00
fallenbagel
d90fc2de1c ci: github repository container lowercase tag 2023-11-08 13:58:09 +05:00
fallenbagel
3b67d6b0e8 build: revert the hardcoded tag 2023-11-08 13:44:37 +05:00
fallenbagel
38348accb0 ci(build): hard-coded repository owner name for lowercase naming 2023-11-08 11:46:42 +05:00
fallenbagel
be335c39be ci(build): implement github repository container images
fix #370
2023-11-08 04:57:20 +05:00
Fallenbagel
c25c5cae38 Merge pull request #559 from Fallenbagel/Fallenbagel-patch-1
Add more detailed installation instructions
2023-11-08 04:38:46 +05:00
Fallenbagel
2e059cefc0 Update README.md 2023-11-08 04:28:36 +05:00
Fallenbagel
e540b58f73 Add more detailed installation instructions 2023-11-08 04:16:34 +05:00
Fallenbagel
22b548bad2 Merge pull request #558 from Fallenbagel/all-contributors/add-Br33ce
docs: add Br33ce as a contributor for translation
2023-11-08 03:42:57 +05:00
allcontributors[bot]
c4adbdb3a8 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:42:49 +00:00
allcontributors[bot]
e5d565b435 docs: update README.md [skip ci] 2023-11-07 22:42:48 +00:00
Fallenbagel
5c531011be Merge pull request #557 from Fallenbagel/all-contributors/add-RickLuiken
docs: add RickLuiken as a contributor for code
2023-11-08 03:42:16 +05:00
allcontributors[bot]
f2b1fd24c2 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:42:07 +00:00
allcontributors[bot]
4be95fade4 docs: update README.md [skip ci] 2023-11-07 22:42:06 +00:00
Fallenbagel
d02f5b0090 Merge pull request #556 from Fallenbagel/all-contributors/add-SirMartin
docs: add SirMartin as a contributor for doc
2023-11-08 03:41:37 +05:00
allcontributors[bot]
d5f2034e69 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:41:27 +00:00
allcontributors[bot]
9059f15291 docs: update README.md [skip ci] 2023-11-07 22:41:26 +00:00
Fallenbagel
b168d04fe6 Merge pull request #555 from Fallenbagel/all-contributors/add-EthanArmbrust
docs: add EthanArmbrust as a contributor for code
2023-11-08 03:40:15 +05:00
allcontributors[bot]
9a51c5b47b docs: update .all-contributorsrc [skip ci] 2023-11-07 22:40:05 +00:00
allcontributors[bot]
ab8efc91d5 docs: update README.md [skip ci] 2023-11-07 22:40:04 +00:00
Fallenbagel
c115f813e5 Merge pull request #554 from Fallenbagel/all-contributors/add-Gauvino
docs: add Gauvino as a contributor for translation
2023-11-08 03:39:29 +05:00
allcontributors[bot]
8967bb9f90 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:39:20 +00:00
allcontributors[bot]
b316b9984d docs: update README.md [skip ci] 2023-11-07 22:39:19 +00:00
Fallenbagel
605a1de98f Merge pull request #553 from Fallenbagel/all-contributors/add-davidfdezalcoba
docs: add davidfdezalcoba as a contributor for code
2023-11-08 03:38:46 +05:00
allcontributors[bot]
74d84a1cad docs: update .all-contributorsrc [skip ci] 2023-11-07 22:38:37 +00:00
allcontributors[bot]
8a7f39994f docs: update README.md [skip ci] 2023-11-07 22:38:36 +00:00
Fallenbagel
6e47834de0 Merge pull request #552 from Fallenbagel/all-contributors/add-d-fendrich
docs: add d-fendrich as a contributor for translation
2023-11-08 03:37:54 +05:00
allcontributors[bot]
14aafbe1d6 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:37:43 +00:00
allcontributors[bot]
445604a615 docs: update README.md [skip ci] 2023-11-07 22:37:42 +00:00
Fallenbagel
fa28f05263 Merge pull request #551 from Fallenbagel/all-contributors/add-jeaboswell
docs: add jeaboswell as a contributor for code
2023-11-08 03:36:57 +05:00
allcontributors[bot]
fd5338167a docs: update .all-contributorsrc [skip ci] 2023-11-07 22:36:47 +00:00
allcontributors[bot]
81b5e8afbd docs: update README.md [skip ci] 2023-11-07 22:36:46 +00:00
Fallenbagel
4fe4e377a6 Merge pull request #550 from Fallenbagel/all-contributors/add-yalagin
docs: add yalagin as a contributor for code
2023-11-08 03:35:59 +05:00
allcontributors[bot]
87a59651b2 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:35:50 +00:00
allcontributors[bot]
3a680c47b6 docs: update README.md [skip ci] 2023-11-07 22:35:49 +00:00
Fallenbagel
44444402a9 Merge pull request #549 from Fallenbagel/all-contributors/add-Pikachu920
docs: add Pikachu920 as a contributor for code
2023-11-08 03:35:14 +05:00
allcontributors[bot]
9140b8d98c docs: update .all-contributorsrc [skip ci] 2023-11-07 22:35:06 +00:00
allcontributors[bot]
2e20fbae1b docs: update README.md [skip ci] 2023-11-07 22:35:05 +00:00
Fallenbagel
6c0d75759f Merge pull request #548 from Fallenbagel/all-contributors/add-GeoffreyCoulaud
docs: add GeoffreyCoulaud as a contributor for translation
2023-11-08 03:34:21 +05:00
allcontributors[bot]
f483062d0e docs: update .all-contributorsrc [skip ci] 2023-11-07 22:34:11 +00:00
allcontributors[bot]
a7cf87f266 docs: update README.md [skip ci] 2023-11-07 22:34:10 +00:00
Fallenbagel
8ef7ec40ae Merge pull request #547 from Fallenbagel/all-contributors/add-andrey4korop
docs: add andrey4korop as a contributor for code, and translation
2023-11-08 03:33:32 +05:00
allcontributors[bot]
3b74002f25 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:33:23 +00:00
allcontributors[bot]
2b1427108c docs: update README.md [skip ci] 2023-11-07 22:33:22 +00:00
Fallenbagel
68b2388205 Merge pull request #546 from Fallenbagel/all-contributors/add-DimitriDR
docs: add DimitriDR as a contributor for translation
2023-11-08 03:32:44 +05:00
allcontributors[bot]
b20c334941 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:32:35 +00:00
allcontributors[bot]
9f2ee0beeb docs: update README.md [skip ci] 2023-11-07 22:32:34 +00:00
Fallenbagel
24a3ee1e77 Merge pull request #545 from Fallenbagel/all-contributors/add-CheChu10
docs: add CheChu10 as a contributor for translation
2023-11-08 03:31:48 +05:00
allcontributors[bot]
510a564a57 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:31:39 +00:00
allcontributors[bot]
6540ba7226 docs: update README.md [skip ci] 2023-11-07 22:31:38 +00:00
Fallenbagel
3291cd08dd Merge pull request #544 from Fallenbagel/all-contributors/add-undone37
docs: add undone37 as a contributor for translation
2023-11-08 03:31:09 +05:00
allcontributors[bot]
a08512ff71 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:30:57 +00:00
allcontributors[bot]
345c67c750 docs: update README.md [skip ci] 2023-11-07 22:30:56 +00:00
Fallenbagel
bff97d2a70 Merge pull request #543 from Fallenbagel/all-contributors/add-darmiel
docs: add darmiel as a contributor for code
2023-11-08 03:29:19 +05:00
allcontributors[bot]
62c289bd65 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:29:10 +00:00
allcontributors[bot]
21cc64eee4 docs: update README.md [skip ci] 2023-11-07 22:29:09 +00:00
Fallenbagel
4a759e64fd Merge pull request #542 from Fallenbagel/all-contributors/add-dd060606
docs: add dd060606 as a contributor for code
2023-11-08 03:27:22 +05:00
allcontributors[bot]
f5122ec652 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:27:07 +00:00
allcontributors[bot]
e9fafeaef8 docs: update README.md [skip ci] 2023-11-07 22:27:06 +00:00
Fallenbagel
8e2c6edd42 Merge pull request #541 from Fallenbagel/all-contributors/add-Smexhy
docs: add Smexhy as a contributor for translation
2023-11-08 03:26:16 +05:00
allcontributors[bot]
532f2882da docs: update .all-contributorsrc [skip ci] 2023-11-07 22:26:06 +00:00
allcontributors[bot]
9e73eaa5a3 docs: update README.md [skip ci] 2023-11-07 22:26:05 +00:00
Fallenbagel
8ef2815b44 Merge pull request #540 from Fallenbagel/all-contributors/add-NicolaiVdS
docs: add NicolaiVdS as a contributor for code
2023-11-08 03:24:42 +05:00
allcontributors[bot]
63d4ab958a docs: update .all-contributorsrc [skip ci] 2023-11-07 22:24:28 +00:00
allcontributors[bot]
b031b58598 docs: update README.md [skip ci] 2023-11-07 22:24:27 +00:00
Fallenbagel
bdd45231e1 Merge pull request #539 from Fallenbagel/all-contributors/add-jab416171
docs: add jab416171 as a contributor for doc
2023-11-08 03:23:16 +05:00
allcontributors[bot]
a38db77c8e docs: update .all-contributorsrc [skip ci] 2023-11-07 22:23:06 +00:00
allcontributors[bot]
21fa447da6 docs: update README.md [skip ci] 2023-11-07 22:23:05 +00:00
Fallenbagel
87bd130420 Merge pull request #538 from Fallenbagel/all-contributors/add-CyferShepard
docs: add CyferShepard as a contributor for code
2023-11-08 03:21:46 +05:00
allcontributors[bot]
9a9ec41d92 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:21:37 +00:00
allcontributors[bot]
e81a305f4d docs: update README.md [skip ci] 2023-11-07 22:21:36 +00:00
Fallenbagel
144980136e Merge pull request #537 from Fallenbagel/all-contributors/add-sambartik
docs: add sambartik as a contributor for code
2023-11-08 03:20:50 +05:00
allcontributors[bot]
f6e90de708 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:20:41 +00:00
allcontributors[bot]
95636c4825 docs: update README.md [skip ci] 2023-11-07 22:20:40 +00:00
Fallenbagel
aa05235392 Merge pull request #536 from Fallenbagel/all-contributors/add-boring-dragon
docs: add boring-dragon as a contributor for code
2023-11-08 03:19:59 +05:00
allcontributors[bot]
84bfc5c363 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:19:46 +00:00
allcontributors[bot]
2f2427f125 docs: update README.md [skip ci] 2023-11-07 22:19:45 +00:00
Fallenbagel
1ac2a2a909 Merge pull request #535 from Fallenbagel/all-contributors/add-jsl9208
docs: add jsl9208 as a contributor for code
2023-11-08 03:18:41 +05:00
allcontributors[bot]
44e368cb1b docs: update .all-contributorsrc [skip ci] 2023-11-07 22:18:02 +00:00
allcontributors[bot]
9bf20b76fa docs: update README.md [skip ci] 2023-11-07 22:18:01 +00:00
Fallenbagel
2a7128c390 Merge pull request #534 from Fallenbagel/all-contributors/add-Jumail
docs: add Jumail as a contributor for review
2023-11-08 03:15:53 +05:00
allcontributors[bot]
8e93d351fd docs: update .all-contributorsrc [skip ci] 2023-11-07 22:15:35 +00:00
allcontributors[bot]
4acec9aeb9 docs: update README.md [skip ci] 2023-11-07 22:15:34 +00:00
Fallenbagel
51b655e364 Merge pull request #532 from Fallenbagel/all-contributors/add-notfakie
docs: add notfakie as a contributor for code
2023-11-08 03:14:20 +05:00
allcontributors[bot]
f658e5ee66 docs: update .all-contributorsrc [skip ci] 2023-11-07 22:11:42 +00:00
allcontributors[bot]
9021e60d11 docs: update README.md [skip ci] 2023-11-07 22:11:41 +00:00
fallenbagel
df510820fa chore: [skip ci] added skipCi to all-contributorsrc temporarily 2023-11-08 03:09:07 +05:00
Fallenbagel
26f90b0d7f Merge pull request #531 from Fallenbagel/all-contributors/add-seanzhang98
docs: add seanzhang98 as a contributor for translation, and code
2023-11-08 03:08:26 +05:00
allcontributors[bot]
d7ba80d502 docs: update .all-contributorsrc 2023-11-07 22:07:29 +00:00
allcontributors[bot]
96e90c1e7e docs: update README.md 2023-11-07 22:07:28 +00:00
Fallenbagel
559b7ff018 Merge pull request #530 from Fallenbagel/all-contributors/add-Fallenbagel
docs: add Fallenbagel as a contributor for code, and maintenance
2023-11-08 02:55:09 +05:00
allcontributors[bot]
dd08f5e7cf docs: update .all-contributorsrc 2023-11-07 21:54:24 +00:00
allcontributors[bot]
0730e17932 docs: update README.md 2023-11-07 21:54:23 +00:00
fallenbagel
a32307e6cf docs: [skip ci] removed contributor block so all-contributors can handle it 2023-11-08 02:51:26 +05:00
fallenbagel
f9bd02553c docs: [skip ci] add in current project allcontributors only
As allcontributors bot does not support having two lists of allcontributors seperately,
unfortunately had to remove upstream contributors from the .all-contributorsrc. However, they will
be added manually by @Fallenbagel to the README.md
2023-11-08 02:39:46 +05:00
fallenbagel
d039e87da4 docs: update README to accomodate both upstream and downstream contributor list seperately 2023-11-08 02:27:30 +05:00
fallenbagel
4347728a1b docs: [skip ci] change contributor settings to add both upstream and downstream contributors
This commit changes the contributorrc for allcontributors bot so we can add both overseerr and
jellyseerr contributors to the list
2023-11-08 02:16:18 +05:00
Fallenbagel
68f7f397d3 Merge pull request #527 from Fallenbagel/fix-local-watchlists
fix(watchlist): discover local watchlist item display and profile local watchlist slider visibility
2023-11-08 01:34:04 +05:00
fallenbagel
8c82a61450 fix: fix the translations for watchlist permissions and userSettings page 2023-11-08 01:24:18 +05:00
fallenbagel
67bde68596 refactor: cleans up local watchlist logic and fixes translation extractions 2023-11-08 01:04:20 +05:00
fallenbagel
3cb9494e62 fix(watchlist): discover local watchlist item display and profile local watchlist slider visibility
Previously when you expand the `Your Watchlist` slider from the discover page to see all your
watchlist items, you only see the first 20 items. This commit fixes that so you can see all your
local watchlist items when you expand that slider. In addition, this commit also fixes the visiblity
of profile watchlist slider for local watchlists
2023-11-08 00:41:28 +05:00
fallenbagel
f92231850c build(snap): remove rm .gitbook.yaml line to fix snap builds 2023-11-07 05:34:19 +05:00
fallenbagel
8f9d3f7fbd build(snap): add frozen-lockfile and increase network timeout for yarn install 2023-11-07 05:24:50 +05:00
fallenbagel
2b7dab2765 build(snap): add yarn install before yarn build 2023-11-07 05:21:15 +05:00
fallenbagel
9ac56a4057 build(snap): use nil package and try to setup node in override-build step 2023-11-07 05:17:39 +05:00
fallenbagel
e8ee6f9e32 build(snap): fix path for the build-environment 2023-11-07 05:07:55 +05:00
fallenbagel
9348cdfd01 build(snap): changes node-js plugin to npm plugin for Core20
In an attempt to fix version compatibility of `GLIBC_2.28` base was upgraded from core18 to core20.
Node-js plugin was deprecated for core20 and instead npm plugin has to be used. As npm plugin cannot
specify the package manager to use, yarn is now installed globally during the override-build phase.
2023-11-07 04:58:28 +05:00
fallenbagel
40c739c5a4 ci(build): changes the base of the snap build to fix compatibility issues with GLIBC version
Changes base to core20 in an attempt to fix the error `node: /lib/x86_64-linux-gnu/libc.so.6:
version `GLIBC_2.28' not found (required by node)` during snap builds
2023-11-07 04:42:36 +05:00
Fallenbagel
364fb46805 Merge pull request #526 from Fallenbagel/fix-forget-password-button
fix(jellyfinlogin): use externalHostname if set for forgetpassword link
2023-11-07 04:26:11 +05:00
fallenbagel
405f6bbb7f fix(jellyfinlogin): use externalHostname if set for forgetpassword link
Implemented dynamic URL generation for the 'Forgot Password' feature. If jellyfin external hostname
is set, the URL is generated based on it; otherwise, jellyfin hostname is used as the base URL. The
URL includes additional parameters to handle emby support.

fix #199, fix #424, re #212
2023-11-07 04:13:19 +05:00
Fallenbagel
9a7a98b75e Merge pull request #525 from Fallenbagel/fix-ukranian-lang-code
fix(langcode): fixes the ukranian language code
2023-11-07 03:37:00 +05:00
fallenbagel
dc67aaaf53 fix(langcode): fixes the ukranian language code
This changes the ukranian language code from ua to uk to fit to ISO 639-1 format that the tmdb api
uses.

fix #504
2023-11-07 02:37:12 +05:00
Fallenbagel
31bc6ca612 Merge pull request #524 from Fallenbagel/fix-library-sync-for-ldap-support
revert(jellyfinapi): reverts #450 as it broke library sync support for local accounts using LDAP
2023-11-07 02:09:41 +05:00
69 changed files with 2330 additions and 1294 deletions

File diff suppressed because it is too large Load Diff

3
.github/FUNDING.yml vendored
View File

@@ -1,2 +1 @@
github: [sct]
patreon: overseerr
github: [Fallenbagel]

View File

@@ -19,7 +19,7 @@ body:
id: version
attributes:
label: Version
description: What version of Overseerr are you running? (You can find this in Settings → About → Version.)
description: What version of Jellyseerr are you running? (You can find this in Settings → About → Version.)
validations:
required: true
- type: textarea
@@ -87,5 +87,5 @@ body:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/fallenbagel/jellyseerr/blob/develop/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow Overseerr's Code of Conduct
- label: I agree to follow Jellyseerr's Code of Conduct
required: true

View File

@@ -2,7 +2,7 @@ blank_issues_enabled: false
contact_links:
- name: 💬 Support via Discord
url: https://discord.gg/ckbvBtDJgC
about: Chat with other users and the Overseerr dev team
about: Chat with other users and the Jellyseerr dev team
- name: 💬 Support via GitHub Discussions
url: https://github.com/fallenbagel/jellyseerr/discussions
about: Ask questions and discuss with other community members

View File

@@ -33,5 +33,5 @@ body:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/fallenbagel/jellyseerr/blob/develop/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow Overseerr's Code of Conduct
- label: I agree to follow Jellyseerr's Code of Conduct
required: true

View File

@@ -50,6 +50,11 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set lower case owner name
run: |
echo "OWNER_LC=${OWNER,,}" >>${GITHUB_ENV}
env:
OWNER: ${{ github.repository_owner }}
- name: Build and push
uses: docker/build-push-action@v3
with:
@@ -61,6 +66,7 @@ jobs:
COMMIT_TAG=${{ github.sha }}
tags: |
fallenbagel/jellyseerr:develop
ghcr.io/${{ env.OWNER_LC }}/jellyseerr:develop
discord:
name: Send Discord Notification

View File

@@ -29,7 +29,7 @@ jobs:
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
build-args: |
COMMIT_TAG=${{ github.sha }}

View File

@@ -1,4 +1,4 @@
# Contributing to Overseerr
# Contributing to Jellyseerr
All help is welcome and greatly appreciated! If you would like to contribute to the project, the following instructions should get you started...
@@ -17,7 +17,7 @@ All help is welcome and greatly appreciated! If you would like to contribute to
1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository to your own GitHub account and [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device:
```bash
git clone https://github.com/YOUR_USERNAME/overseerr.git
git clone https://github.com/YOUR_USERNAME/jellyseerr.git
cd overseerr/
```
@@ -97,9 +97,9 @@ When adding new UI text, please try to adhere to the following guidelines:
## Translation
We use [Weblate](https://hosted.weblate.org/engage/overseerr/) for our translations, and your help with localizing Overseerr would be greatly appreciated! If your language is not listed below, please [open a feature request](https://github.com/fallenbagel/jellyseerr/issues/new/choose).
We use [Weblate](https://jellyseerr.borgcube.de/projects/jellyseerr/jellyseerr-frontend/) for our translations, and your help with localizing Overseerr would be greatly appreciated! If your language is not listed below, please [open a feature request](https://github.com/fallenbagel/jellyseerr/issues/new/choose).
<a href="https://hosted.weblate.org/engage/overseerr/"><img src="https://hosted.weblate.org/widgets/overseerr/-/overseerr-frontend/multi-auto.svg" alt="Translation status" /></a>
<a href="https://jellyseerr.borgcube.de/engage/jellysseerr/"><img src="https://jellyseerr.borgcube.de/widget/jellyseerr/multi-auto.svg" alt="Translation status" /></a>
## Attribution

View File

@@ -36,6 +36,9 @@ RUN echo "{\"commitTag\": \"${COMMIT_TAG}\"}" > committag.json
FROM node:18.18-alpine
# Metadata for Github Package Registry
LABEL org.opencontainers.image.source="https://github.com/Fallenbagel/jellyseerr"
WORKDIR /app
RUN apk add --no-cache tzdata tini && rm -rf /tmp/*

184
README.md
View File

@@ -2,23 +2,28 @@
<img src="./public/logo_full.svg" alt="Jellyseerr" style="margin: 20px 0;">
</p>
<p align="center">
<a href="https://discord.gg/ckbvBtDJgC"><img src="https://img.shields.io/badge/Discord-Chat-lightgrey" alt="Discord"></a>
<img src="https://github.com/Fallenbagel/jellyseerr/actions/workflows/release.yml/badge.svg" alt="Jellyseerr Release" />
<img src="https://github.com/Fallenbagel/jellyseerr/actions/workflows/ci.yml/badge.svg" alt="Jellyseerr CI">
</p>
<p align="center">
<a href="https://discord.gg/ckbvBtDJgC"><img src="https://img.shields.io/discord/952656177924300932" alt="Discord"></a>
<a href="https://hub.docker.com/r/fallenbagel/jellyseerr"><img src="https://img.shields.io/docker/pulls/fallenbagel/jellyseerr" alt="Docker pulls"></a>
<a href="http://jellyseerr.borgcube.de/engage/jellyseerr/"><img src="http://jellyseerr.borgcube.de/widget/jellyseerr/jellyseerr-frontend/svg-badge.svg" alt="Translation status" /></a>
<a href="https://github.com/fallenbagel/jellyseerr/blob/develop/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/fallenbagel/jellyseerr"></a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a href="#contributors-"><img alt="All Contributors" src="https://img.shields.io/badge/all_contributors-99-orange.svg"/></a>
<a href="#contributors-"><img alt="All Contributors" src="https://img.shields.io/badge/all_contributors-34-orange.svg"/></a>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
**Jellyseerr** is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers!
**Jellyseerr** is a free and open source software application for managing requests for your media library.
It is a fork of [Overseerr](https://github.com/sct/overseerr) built to bring support for [Jellyfin](https://github.com/jellyfin/jellyfin) & [Emby](https://github.com/MediaBrowser/Emby) media servers!
_The original Overseerr team have been busy and Jellyfin/Emby support aren't on their roadmap, so we started this project as we wanted to bring the Overseerr experience to the Jellyfin/Emby Community!_
## Current Features
- Full Jellyfin/Emby/Plex integration. Authenticate and manage user access with Jellyfin/Emby/Plex!
- Supports Movies, Shows, Mixed Libraries!
- Full Jellyfin/Emby/Plex integration including authentication with user import & management
- Supports Movies, Shows and Mixed Libraries
- Ability to change email addresses for smtp purposes
- Ability to import all jellyfin/emby users
- Easy integration with your existing services. Currently, Jellyseerr supports Sonarr and Radarr. More to come!
- Jellyfin/Emby/Plex library scan, to keep track of the titles which are already available.
- Customizable request system, which allows users to request individual seasons or movies in a friendly, easy-to-use interface.
@@ -35,72 +40,73 @@ With more features on the way! Check out our [issue tracker](https://github.com/
#### Pre-requisite (Important)
_*On Jellyfin/Emby, ensure the `settings > Home > Automatically group content from the following folders into views such as 'Movies', 'Music' and 'TV'` is turned off*_
_*On Jellyfin/Emby, ensure the `Settings > Home > Automatically group content from the following folders into views such as 'Movies', 'Music' and 'TV'` is turned off*_
### Launching Jellyseerr using Docker
### Launching Jellyseerr using Docker (Recommended)
Check out our dockerhub for instructions on how to install and run Jellyseerr:
Check out our docker hub for instructions on how to install and run Jellyseerr:
https://hub.docker.com/r/fallenbagel/jellyseerr
### Launching Jellyseerr manually:
### Building from source (ADVANCED):
#### Windows
Pre-requisites:
- Nodejs (atleast LTS version)
- Yarn
- Download the source code from the github (Either develop branch or main for stable)
- Nodejs [v18](https://nodejs.org/download/release/v18.18.2)
- [Yarn](https://classic.yarnpkg.com/lang/en/docs/install)
- Download/git clone the source code from the github (Either develop branch or main for stable)
```bash
```cmd
npm i -g win-node-env
yarn install
set CYPRESS_INSTALL_BINARY=0
yarn install --frozen-lockfile --network-timeout 1000000
yarn run build
yarn start
```
(You can use task scheduler to run a bat script with `@echo off` and `yarn start` to run jellyseerr in the background)
_To set env variables such as `JELLYFIN_TYPE=emby` create a file called `.env` in the root directory of jellyseerr_
#### Linux
Pre-requisites:
**Pre-requisites:**
- Nodejs (atleast LTS version)
- Yarn
- Nodejs [v18](https://nodejs.org/en/download/package-manager)
- [Yarn](https://classic.yarnpkg.com/lang/en/docs/install) (on Debian based distros, the package manager provided `yarn` is different and is a package called cmdlet. You can remove that using `apt-remove cmdlet` then install yarn using `npm install -g yarn`)
- Git
**Steps:**
1. Assuming you want the root folder for the jellyseerr source code to be cloned to `/opt`
```bash
cd /opt
```
2. Then execute the following commands to clone and checkout to the stable version
```bash
git clone https://github.com/Fallenbagel/jellyseerr.git && cd jellyseerr
git checkout main #if you want to run stable instead of develop
yarn install
yarn run build
yarn start
git checkout main
```
_Systemd-service:_
3. Then install the dependencies and build the dist
```bash
CYPRESS_INSTALL_BINARY=0 yarn install --frozen-lockfile --network-timeout 1000000
yarn run build
```
4. Now you can start jellyseerr using `yarn start` and opening http://localhost:5055 in your browser.
5. If you want to run jellyseerr as a _Systemd-service:_
- assuming jellyseerr was cloned to `/opt/`
and the environmentfile is located at `/etc/jellyseerr`
- first create the environment file at `/etc/jellyseerr/jellyseerr.conf`
service:
```
[Unit]
Description=Jellyseerr Service
Wants=network-online.target
After=network-online.target
[Service]
EnvironmentFile=/etc/jellyseerr/jellyseerr.conf
Environment=NODE_ENV=production
Type=exec
Restart=on-failure
WorkingDirectory=/opt/jellyseerr
ExecStart=/root/.nvm/versions/node/v18.7.0/bin/node dist/index.js
[Install]
WantedBy=multi-user.target
```
Environmentfile:
Environment file:
```
# Jellyseerr's default port is 5055, if you want to use both, change this.
@@ -114,9 +120,34 @@ PORT=5055
# JELLYFIN_TYPE=emby
```
- Then run the command `which node` to find your node path (assuming it's at `/usr/bin/node`)
- Then create the service file using `sudo systemctl edit jellyseerr.service` or creating and editing a file at `/etc/systemd/system/jellyseerr.service`
Service file contents:
```
[Unit]
Description=Jellyseerr Service
Wants=network-online.target
After=network-online.target
[Service]
EnvironmentFile=/etc/jellyseerr/jellyseerr.conf
Environment=NODE_ENV=production
Type=exec
Restart=on-failure
WorkingDirectory=/opt/jellyseerr
ExecStart=/usr/bin/node dist/index.js
[Install]
WantedBy=multi-user.target
```
### Packages:
Archlinux: [AUR](https://aur.archlinux.org/packages/jellyseerr)
Nixpkg: [Nixpkg](https://search.nixos.org/packages?channel=unstable&show=jellyseerr)
Snap: [Snap](https://snapcraft.io/jellyseerr)
## Preview
@@ -148,9 +179,67 @@ You can help improve Jellyseerr too! Check out our [Contribution Guide](https://
Thanks goes to these wonderful people from Overseerr ([emoji key](https://allcontributors.org/docs/en/emoji-key)) and all those that contributed directly to Jellyseerr:
### Jellyseerr Contributors ✨
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Fallenbagel"><img src="https://avatars.githubusercontent.com/u/98979876?v=4?s=100" width="100px;" alt="Fallenbagel"/><br /><sub><b>Fallenbagel</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=Fallenbagel" title="Code">💻</a> <a href="#maintenance-Fallenbagel" title="Maintenance">🚧</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/seanzhang98"><img src="https://avatars.githubusercontent.com/u/34902361?v=4?s=100" width="100px;" alt="Sean"/><br /><sub><b>Sean</b></sub></a><br /><a href="#translation-seanzhang98" title="Translation">🌍</a> <a href="https://github.com/Fallenbagel/jellyseerr/commits?author=seanzhang98" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notfakie"><img src="https://avatars.githubusercontent.com/u/103784113?v=4?s=100" width="100px;" alt="notfakie"/><br /><sub><b>notfakie</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=notfakie" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jumail"><img src="https://avatars.githubusercontent.com/u/7672055?v=4?s=100" width="100px;" alt="Mohamed Jumail"/><br /><sub><b>Mohamed Jumail</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/pulls?q=is%3Apr+reviewed-by%3AJumail" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.heywhale.com"><img src="https://avatars.githubusercontent.com/u/4048787?v=4?s=100" width="100px;" alt="Shilong Jiang"/><br /><sub><b>Shilong Jiang</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=jsl9208" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://jinas.me"><img src="https://avatars.githubusercontent.com/u/28459081?v=4?s=100" width="100px;" alt="Boring Dragon"/><br /><sub><b>Boring Dragon</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=boring-dragon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sambartik"><img src="https://avatars.githubusercontent.com/u/63553146?v=4?s=100" width="100px;" alt="Samuel Bartík"/><br /><sub><b>Samuel Bartík</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=sambartik" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CyferShepard"><img src="https://avatars.githubusercontent.com/u/24864904?v=4?s=100" width="100px;" alt="Thegan Govender"/><br /><sub><b>Thegan Govender</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=CyferShepard" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jab416171"><img src="https://avatars.githubusercontent.com/u/345752?v=4?s=100" width="100px;" alt="jab416171"/><br /><sub><b>jab416171</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=jab416171" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://nvds.be"><img src="https://avatars.githubusercontent.com/u/5257222?v=4?s=100" width="100px;" alt="Nicolai Van der Storm"/><br /><sub><b>Nicolai Van der Storm</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=NicolaiVdS" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Smexhy"><img src="https://avatars.githubusercontent.com/u/4880625?v=4?s=100" width="100px;" alt="Smexhy"/><br /><sub><b>Smexhy</b></sub></a><br /><a href="#translation-Smexhy" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://dd06-dev.fr"><img src="https://avatars.githubusercontent.com/u/58089504?v=4?s=100" width="100px;" alt="dd060606"/><br /><sub><b>dd060606</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=dd060606" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://qwer.tz"><img src="https://avatars.githubusercontent.com/u/71837281?v=4?s=100" width="100px;" alt="Daniel"/><br /><sub><b>Daniel</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=darmiel" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/undone37"><img src="https://avatars.githubusercontent.com/u/10513808?v=4?s=100" width="100px;" alt="undone37"/><br /><sub><b>undone37</b></sub></a><br /><a href="#translation-undone37" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CheChu10"><img src="https://avatars.githubusercontent.com/u/32913133?v=4?s=100" width="100px;" alt="Chechu García"/><br /><sub><b>Chechu García</b></sub></a><br /><a href="#translation-CheChu10" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DimitriDR"><img src="https://avatars.githubusercontent.com/u/56969769?v=4?s=100" width="100px;" alt="Dimitri"/><br /><sub><b>Dimitri</b></sub></a><br /><a href="#translation-DimitriDR" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andrey4korop"><img src="https://avatars.githubusercontent.com/u/24610708?v=4?s=100" width="100px;" alt="andrey4korop"/><br /><sub><b>andrey4korop</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=andrey4korop" title="Code">💻</a> <a href="#translation-andrey4korop" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://geoffrey-coulaud.fr"><img src="https://avatars.githubusercontent.com/u/20744730?v=4?s=100" width="100px;" alt="Geoffrey Coulaud"/><br /><sub><b>Geoffrey Coulaud</b></sub></a><br /><a href="#translation-GeoffreyCoulaud" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Pikachu920"><img src="https://avatars.githubusercontent.com/u/28607612?v=4?s=100" width="100px;" alt="Pikachu920"/><br /><sub><b>Pikachu920</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=Pikachu920" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yalagin"><img src="https://avatars.githubusercontent.com/u/12879142?v=4?s=100" width="100px;" alt="Maxim Yalagin"/><br /><sub><b>Maxim Yalagin</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=yalagin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jeaboswell"><img src="https://avatars.githubusercontent.com/u/11653068?v=4?s=100" width="100px;" alt="Jesse Boswell"/><br /><sub><b>Jesse Boswell</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=jeaboswell" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/d-fendrich"><img src="https://avatars.githubusercontent.com/u/27904138?v=4?s=100" width="100px;" alt="d-fendrich"/><br /><sub><b>d-fendrich</b></sub></a><br /><a href="#translation-d-fendrich" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/davidfdezalcoba"><img src="https://avatars.githubusercontent.com/u/15996018?v=4?s=100" width="100px;" alt="David Fernández Alcoba"/><br /><sub><b>David Fernández Alcoba</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=davidfdezalcoba" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Gauvino"><img src="https://avatars.githubusercontent.com/u/68083474?v=4?s=100" width="100px;" alt="Gauvino"/><br /><sub><b>Gauvino</b></sub></a><br /><a href="#translation-Gauvino" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/EthanArmbrust"><img src="https://avatars.githubusercontent.com/u/22754714?v=4?s=100" width="100px;" alt="EthanArmbrust"/><br /><sub><b>EthanArmbrust</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=EthanArmbrust" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.piribisoft.com"><img src="https://avatars.githubusercontent.com/u/854646?v=4?s=100" width="100px;" alt="Eduardo"/><br /><sub><b>Eduardo</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=SirMartin" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RickLuiken"><img src="https://avatars.githubusercontent.com/u/34110371?v=4?s=100" width="100px;" alt="RickLuiken"/><br /><sub><b>RickLuiken</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=RickLuiken" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Br33ce"><img src="https://avatars.githubusercontent.com/u/124933490?v=4?s=100" width="100px;" alt="Br33ce"/><br /><sub><b>Br33ce</b></sub></a><br /><a href="#translation-Br33ce" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://athfan.com"><img src="https://avatars.githubusercontent.com/u/13810742?v=4?s=100" width="100px;" alt="Athfan Khaleel"/><br /><sub><b>Athfan Khaleel</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=athphane" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mdll23"><img src="https://avatars.githubusercontent.com/u/142844478?v=4?s=100" width="100px;" alt="Michael Dallinger"/><br /><sub><b>Michael Dallinger</b></sub></a><br /><a href="#translation-mdll23" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xeruf"><img src="https://avatars.githubusercontent.com/u/13354331?v=4?s=100" width="100px;" alt="Janek"/><br /><sub><b>Janek</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=xeruf" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://aleksasiriski.dev"><img src="https://avatars.githubusercontent.com/u/31509435?v=4?s=100" width="100px;" alt="Aleksa Siriški"/><br /><sub><b>Aleksa Siriški</b></sub></a><br /><a href="#infra-aleksasiriski" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://danishhumair.com"><img src="https://avatars.githubusercontent.com/u/121830048?v=4?s=100" width="100px;" alt="Danish Humair"/><br /><sub><b>Danish Humair</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=Danish-H" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://arm0.red"><img src="https://avatars.githubusercontent.com/u/16858514?v=4?s=100" width="100px;" alt="Stephen Harris"/><br /><sub><b>Stephen Harris</b></sub></a><br /><a href="https://github.com/Fallenbagel/jellyseerr/commits?author=trackmastersteve" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
### Overseerr Contributors ✨
<table>
<tbody>
<tr>
@@ -284,8 +373,3 @@ Thanks goes to these wonderful people from Overseerr ([emoji key](https://allcon
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

View File

@@ -368,6 +368,9 @@ components:
externalHostname:
type: string
example: 'http://my.jellyfin.host'
jellyfinForgotPasswordUrl:
type: string
example: 'http://my.jellyfin.host/web/index.html#!/forgotpassword.html'
adminUser:
type: string
example: 'admin'

View File

@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import availabilitySync from '@server/lib/availabilitySync';
import logger from '@server/logger';
import type { AxiosInstance } from 'axios';
import axios from 'axios';
@@ -8,6 +9,9 @@ export interface JellyfinUserResponse {
ServerId: string;
ServerName: string;
Id: string;
Policy: {
IsAdministrator: boolean;
};
PrimaryImageTag?: string;
}
@@ -241,7 +245,9 @@ class JellyfinAPI {
}
}
public async getItemData(id: string): Promise<JellyfinLibraryItemExtended> {
public async getItemData(
id: string
): Promise<JellyfinLibraryItemExtended | undefined> {
try {
const contents = await this.axios.get<any>(
`/Users/${this.userId}/Items/${id}`
@@ -249,6 +255,11 @@ class JellyfinAPI {
return contents.data;
} catch (e) {
if (availabilitySync.running) {
if (e.response && e.response.status === 500) {
return undefined;
}
}
logger.error(
`Something went wrong while getting library content from the Jellyfin server: ${e.message}`,
{ label: 'Jellyfin API' }
@@ -261,9 +272,7 @@ class JellyfinAPI {
try {
const contents = await this.axios.get<any>(`/Shows/${seriesID}/Seasons`);
return contents.data.Items.filter(
(item: JellyfinLibraryItem) => item.LocationType !== 'Virtual'
);
return contents.data.Items;
} catch (e) {
logger.error(
`Something went wrong while getting the list of seasons from the Jellyfin server: ${e.message}`,

View File

@@ -151,11 +151,11 @@ class Media {
@Column({ nullable: true, type: 'varchar' })
public ratingKey4k?: string | null;
@Column({ nullable: true })
public jellyfinMediaId?: string;
@Column({ nullable: true, type: 'varchar' })
public jellyfinMediaId?: string | null;
@Column({ nullable: true })
public jellyfinMediaId4k?: string;
@Column({ nullable: true, type: 'varchar' })
public jellyfinMediaId4k?: string | null;
public serviceUrl?: string;
public serviceUrl4k?: string;

View File

@@ -22,7 +22,9 @@ export interface SettingsAboutResponse {
export interface PublicSettingsResponse {
jellyfinHost?: string;
jellyfinExternalHost?: string;
jellyfinServerName?: string;
jellyfinForgotPasswordUrl?: string;
initialized: boolean;
applicationTitle: string;
applicationUrl: string;

View File

@@ -1,6 +1,11 @@
import { MediaServerType } from '@server/constants/server';
import availabilitySync from '@server/lib/availabilitySync';
import downloadTracker from '@server/lib/downloadtracker';
import ImageProxy from '@server/lib/imageproxy';
import {
jellyfinFullScanner,
jellyfinRecentScanner,
} from '@server/lib/scanners/jellyfin';
import { plexFullScanner, plexRecentScanner } from '@server/lib/scanners/plex';
import { radarrScanner } from '@server/lib/scanners/radarr';
import { sonarrScanner } from '@server/lib/scanners/sonarr';
@@ -10,7 +15,6 @@ import watchlistSync from '@server/lib/watchlistsync';
import logger from '@server/logger';
import random from 'lodash/random';
import schedule from 'node-schedule';
import { jobJellyfinFullSync, jobJellyfinRecentSync } from './jellyfinsync';
interface ScheduledJob {
id: JobId;
@@ -73,38 +77,38 @@ export const startJobs = (): void => {
// Run recently added jellyfin sync every 5 minutes
scheduledJobs.push({
id: 'jellyfin-recently-added-scan',
name: 'Jellyfin Recently Added Sync',
name: 'Jellyfin Recently Added Scan',
type: 'process',
interval: 'minutes',
cronSchedule: jobs['jellyfin-recently-added-scan'].schedule,
job: schedule.scheduleJob(
jobs['jellyfin-recently-added-scan'].schedule,
() => {
logger.info('Starting scheduled job: Jellyfin Recently Added Sync', {
logger.info('Starting scheduled job: Jellyfin Recently Added Scan', {
label: 'Jobs',
});
jobJellyfinRecentSync.run();
jellyfinRecentScanner.run();
}
),
running: () => jobJellyfinRecentSync.status().running,
cancelFn: () => jobJellyfinRecentSync.cancel(),
running: () => jellyfinRecentScanner.status().running,
cancelFn: () => jellyfinRecentScanner.cancel(),
});
// Run full jellyfin sync every 24 hours
scheduledJobs.push({
id: 'jellyfin-full-scan',
name: 'Jellyfin Full Library Sync',
name: 'Jellyfin Full Library Scan',
type: 'process',
interval: 'hours',
cronSchedule: jobs['jellyfin-full-scan'].schedule,
job: schedule.scheduleJob(jobs['jellyfin-full-scan'].schedule, () => {
logger.info('Starting scheduled job: Jellyfin Full Sync', {
logger.info('Starting scheduled job: Jellyfin Full Scan', {
label: 'Jobs',
});
jobJellyfinFullSync.run();
jellyfinFullScanner.run();
}),
running: () => jobJellyfinFullSync.status().running,
cancelFn: () => jobJellyfinFullSync.cancel(),
running: () => jellyfinFullScanner.status().running,
cancelFn: () => jellyfinFullScanner.cancel(),
});
}
@@ -164,7 +168,7 @@ export const startJobs = (): void => {
});
// Checks if media is still available in plex/sonarr/radarr libs
/* scheduledJobs.push({
scheduledJobs.push({
id: 'availability-sync',
name: 'Media Availability Sync',
type: 'process',
@@ -179,7 +183,6 @@ export const startJobs = (): void => {
running: () => availabilitySync.running,
cancelFn: () => availabilitySync.cancel(),
});
*/
// Run download sync every minute
scheduledJobs.push({

View File

@@ -1,9 +1,12 @@
import type { JellyfinLibraryItem } from '@server/api/jellyfin';
import JellyfinAPI from '@server/api/jellyfin';
import type { PlexMetadata } from '@server/api/plexapi';
import PlexAPI from '@server/api/plexapi';
import RadarrAPI, { type RadarrMovie } from '@server/api/servarr/radarr';
import type { SonarrSeason, SonarrSeries } from '@server/api/servarr/sonarr';
import SonarrAPI from '@server/api/servarr/sonarr';
import { MediaRequestStatus, MediaStatus } from '@server/constants/media';
import { MediaServerType } from '@server/constants/server';
import { getRepository } from '@server/datasource';
import Media from '@server/entity/Media';
import MediaRequest from '@server/entity/MediaRequest';
@@ -18,14 +21,20 @@ class AvailabilitySync {
public running = false;
private plexClient: PlexAPI;
private plexSeasonsCache: Record<string, PlexMetadata[]>;
private jellyfinClient: JellyfinAPI;
private jellyfinSeasonsCache: Record<string, JellyfinLibraryItem[]>;
private sonarrSeasonsCache: Record<string, SonarrSeason[]>;
private radarrServers: RadarrSettings[];
private sonarrServers: SonarrSettings[];
async run() {
const settings = getSettings();
const mediaServerType = getSettings().main.mediaServerType;
this.running = true;
this.plexSeasonsCache = {};
this.jellyfinSeasonsCache = {};
this.sonarrSeasonsCache = {};
this.radarrServers = settings.radarr.filter((server) => server.syncEnabled);
this.sonarrServers = settings.sonarr.filter((server) => server.syncEnabled);
@@ -37,13 +46,53 @@ class AvailabilitySync {
const pageSize = 50;
const userRepository = getRepository(User);
const admin = await userRepository.findOne({
select: { id: true, plexToken: true },
where: { id: 1 },
});
if (admin) {
this.plexClient = new PlexAPI({ plexToken: admin.plexToken });
// If it is plex admin is selected using plexToken if jellyfin admin is selected using jellyfinUserID
let admin = null;
if (mediaServerType === MediaServerType.PLEX) {
admin = await userRepository.findOne({
select: { id: true, plexToken: true },
where: { id: 1 },
});
} else if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
admin = await userRepository.findOne({
where: { id: 1 },
select: [
'id',
'jellyfinAuthToken',
'jellyfinUserId',
'jellyfinDeviceId',
],
order: { id: 'ASC' },
});
}
if (mediaServerType === MediaServerType.PLEX) {
if (admin && admin.plexToken) {
this.plexClient = new PlexAPI({ plexToken: admin.plexToken });
} else {
logger.error('Plex admin is not configured.');
}
} else if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
if (admin) {
this.jellyfinClient = new JellyfinAPI(
settings.jellyfin.hostname ?? '',
admin.jellyfinAuthToken,
admin.jellyfinDeviceId
);
this.jellyfinClient.setUserId(admin.jellyfinUserId ?? '');
} else {
logger.error('Jellyfin admin is not configured.');
}
} else {
logger.error('An admin is not configured.');
}
@@ -60,41 +109,84 @@ class AvailabilitySync {
let movieExists = false;
let movieExists4k = false;
const { existsInPlex } = await this.mediaExistsInPlex(media, false);
const { existsInPlex: existsInPlex4k } = await this.mediaExistsInPlex(
media,
true
);
// if (mediaServerType === MediaServerType.PLEX) {
// await this.mediaExistsInPlex(media, false);
// } else if (
// mediaServerType === MediaServerType.JELLYFIN ||
// mediaServerType === MediaServerType.EMBY
// ) {
// await this.mediaExistsInJellyfin(media, false);
// }
const existsInRadarr = await this.mediaExistsInRadarr(media, false);
const existsInRadarr4k = await this.mediaExistsInRadarr(media, true);
if (existsInPlex || existsInRadarr) {
movieExists = true;
logger.info(
`The non-4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
// plex
if (mediaServerType === MediaServerType.PLEX) {
const { existsInPlex } = await this.mediaExistsInPlex(media, false);
const { existsInPlex: existsInPlex4k } =
await this.mediaExistsInPlex(media, true);
if (existsInPlex || existsInRadarr) {
movieExists = true;
logger.info(
`The non-4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
if (existsInPlex4k || existsInRadarr4k) {
movieExists4k = true;
logger.info(
`The 4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
if (existsInPlex4k || existsInRadarr4k) {
movieExists4k = true;
logger.info(
`The 4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
//jellyfin
if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
const { existsInJellyfin } = await this.mediaExistsInJellyfin(
media,
false
);
const { existsInJellyfin: existsInJellyfin4k } =
await this.mediaExistsInJellyfin(media, true);
if (existsInJellyfin || existsInRadarr) {
movieExists = true;
logger.info(
`The non-4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
if (existsInJellyfin4k || existsInRadarr4k) {
movieExists4k = true;
logger.info(
`The 4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
if (!movieExists && media.status === MediaStatus.AVAILABLE) {
await this.mediaUpdater(media, false);
await this.mediaUpdater(media, false, mediaServerType);
}
if (!movieExists4k && media.status4k === MediaStatus.AVAILABLE) {
await this.mediaUpdater(media, true);
await this.mediaUpdater(media, true, mediaServerType);
}
}
@@ -104,6 +196,8 @@ class AvailabilitySync {
let showExists = false;
let showExists4k = false;
//plex
const { existsInPlex, seasonsMap: plexSeasonsMap = new Map() } =
await this.mediaExistsInPlex(media, false);
const {
@@ -111,6 +205,16 @@ class AvailabilitySync {
seasonsMap: plexSeasonsMap4k = new Map(),
} = await this.mediaExistsInPlex(media, true);
//jellyfin
const {
existsInJellyfin,
seasonsMap: jellyfinSeasonsMap = new Map(),
} = await this.mediaExistsInJellyfin(media, false);
const {
existsInJellyfin: existsInJellyfin4k,
seasonsMap: jellyfinSeasonsMap4k = new Map(),
} = await this.mediaExistsInJellyfin(media, true);
const { existsInSonarr, seasonsMap: sonarrSeasonsMap } =
await this.mediaExistsInSonarr(media, false);
const {
@@ -118,24 +222,60 @@ class AvailabilitySync {
seasonsMap: sonarrSeasonsMap4k,
} = await this.mediaExistsInSonarr(media, true);
if (existsInPlex || existsInSonarr) {
showExists = true;
logger.info(
`The non-4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
//plex
if (mediaServerType === MediaServerType.PLEX) {
if (existsInPlex || existsInSonarr) {
showExists = true;
logger.info(
`The non-4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
if (existsInPlex4k || existsInSonarr4k) {
showExists4k = true;
logger.info(
`The 4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
if (mediaServerType === MediaServerType.PLEX) {
if (existsInPlex4k || existsInSonarr4k) {
showExists4k = true;
logger.info(
`The 4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
//jellyfin
if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
if (existsInJellyfin || existsInSonarr) {
showExists = true;
logger.info(
`The non-4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
if (existsInJellyfin4k || existsInSonarr4k) {
showExists4k = true;
logger.info(
`The 4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,
{
label: 'AvailabilitySync',
}
);
}
}
// Here we will create a final map that will cross compare
@@ -155,11 +295,45 @@ class AvailabilitySync {
filteredSeasonsMap.set(season.seasonNumber, false)
);
const finalSeasons = new Map([
...filteredSeasonsMap,
...plexSeasonsMap,
...sonarrSeasonsMap,
]);
// non-4k
const finalSeasons: Map<number, boolean> = new Map();
if (mediaServerType === MediaServerType.PLEX) {
plexSeasonsMap.forEach((value, key) => {
finalSeasons.set(key, value);
});
filteredSeasonsMap.forEach((value, key) => {
if (!finalSeasons.has(key)) {
finalSeasons.set(key, value);
}
});
sonarrSeasonsMap.forEach((value, key) => {
if (!finalSeasons.has(key)) {
finalSeasons.set(key, value);
}
});
} else if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
jellyfinSeasonsMap.forEach((value, key) => {
finalSeasons.set(key, value);
});
filteredSeasonsMap.forEach((value, key) => {
if (!finalSeasons.has(key)) {
finalSeasons.set(key, value);
}
});
sonarrSeasonsMap.forEach((value, key) => {
if (!finalSeasons.has(key)) {
finalSeasons.set(key, value);
}
});
}
const filteredSeasonsMap4k: Map<number, boolean> = new Map();
@@ -173,18 +347,64 @@ class AvailabilitySync {
filteredSeasonsMap4k.set(season.seasonNumber, false)
);
const finalSeasons4k = new Map([
...filteredSeasonsMap4k,
...plexSeasonsMap4k,
...sonarrSeasonsMap4k,
]);
// 4k
const finalSeasons4k: Map<number, boolean> = new Map();
if (mediaServerType === MediaServerType.PLEX) {
plexSeasonsMap4k.forEach((value, key) => {
finalSeasons4k.set(key, value);
});
filteredSeasonsMap4k.forEach((value, key) => {
if (!finalSeasons4k.has(key)) {
finalSeasons4k.set(key, value);
}
});
sonarrSeasonsMap4k.forEach((value, key) => {
if (!finalSeasons4k.has(key)) {
finalSeasons4k.set(key, value);
}
});
} else if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
jellyfinSeasonsMap4k.forEach((value, key) => {
finalSeasons4k.set(key, value);
});
filteredSeasonsMap4k.forEach((value, key) => {
if (!finalSeasons4k.has(key)) {
finalSeasons4k.set(key, value);
}
});
sonarrSeasonsMap4k.forEach((value, key) => {
if (!finalSeasons4k.has(key)) {
finalSeasons4k.set(key, value);
}
});
}
// TODO: Figure out how to run seasonUpdater for each season
if ([...finalSeasons.values()].includes(false)) {
await this.seasonUpdater(media, finalSeasons, false);
await this.seasonUpdater(
media,
finalSeasons,
false,
mediaServerType
);
}
if ([...finalSeasons4k.values()].includes(false)) {
await this.seasonUpdater(media, finalSeasons4k, true);
await this.seasonUpdater(
media,
finalSeasons4k,
true,
mediaServerType
);
}
if (
@@ -192,7 +412,7 @@ class AvailabilitySync {
(media.status === MediaStatus.AVAILABLE ||
media.status === MediaStatus.PARTIALLY_AVAILABLE)
) {
await this.mediaUpdater(media, false);
await this.mediaUpdater(media, false, mediaServerType);
}
if (
@@ -200,7 +420,7 @@ class AvailabilitySync {
(media.status4k === MediaStatus.AVAILABLE ||
media.status4k === MediaStatus.PARTIALLY_AVAILABLE)
) {
await this.mediaUpdater(media, true);
await this.mediaUpdater(media, true, mediaServerType);
}
}
}
@@ -272,7 +492,11 @@ class AvailabilitySync {
return mediaStatus;
}
private async mediaUpdater(media: Media, is4k: boolean): Promise<void> {
private async mediaUpdater(
media: Media,
is4k: boolean,
mediaServerType: MediaServerType
): Promise<void> {
const mediaRepository = getRepository(Media);
const requestRepository = getRepository(MediaRequest);
@@ -320,17 +544,32 @@ class AvailabilitySync {
mediaStatus === MediaStatus.PROCESSING
? media[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug']
: null;
media[is4k ? 'ratingKey4k' : 'ratingKey'] =
mediaStatus === MediaStatus.PROCESSING
? media[is4k ? 'ratingKey4k' : 'ratingKey']
: null;
if (mediaServerType === MediaServerType.PLEX) {
media[is4k ? 'ratingKey4k' : 'ratingKey'] =
mediaStatus === MediaStatus.PROCESSING
? media[is4k ? 'ratingKey4k' : 'ratingKey']
: null;
} else if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
media[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId'] =
mediaStatus === MediaStatus.PROCESSING
? media[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId']
: null;
}
logger.info(
`The ${is4k ? '4K' : 'non-4K'} ${
media.mediaType === 'movie' ? 'movie' : 'show'
} [TMDB ID ${media.tmdbId}] was not found in any ${
media.mediaType === 'movie' ? 'Radarr' : 'Sonarr'
} and Plex instance. Status will be changed to unknown.`,
} and ${
mediaServerType === MediaServerType.PLEX
? 'plex'
: mediaServerType === MediaServerType.JELLYFIN
? 'jellyfin'
: 'emby'
} instance. Status will be changed to unknown.`,
{ label: 'AvailabilitySync' }
);
@@ -358,7 +597,8 @@ class AvailabilitySync {
private async seasonUpdater(
media: Media,
seasons: Map<number, boolean>,
is4k: boolean
is4k: boolean,
mediaServerType: MediaServerType
): Promise<void> {
const mediaRepository = getRepository(Media);
const seasonRequestRepository = getRepository(SeasonRequest);
@@ -370,6 +610,8 @@ class AvailabilitySync {
);
const seasonKeys = [...seasonsPendingRemoval.keys()];
// let isSeasonRemoved = false;
try {
// Need to check and see if there are any related season
// requests. If they are, we will need to delete them.
@@ -420,7 +662,13 @@ class AvailabilitySync {
media.tmdbId
}] was not found in any ${
media.mediaType === 'tv' ? 'Sonarr' : 'Radarr'
} and Plex instance. Status will be changed to unknown.`,
} and ${
mediaServerType === MediaServerType.PLEX
? 'plex'
: mediaServerType === MediaServerType.JELLYFIN
? 'jellyfin'
: 'emby'
} instance. Status will be changed to unknown.`,
{ label: 'AvailabilitySync' }
);
} catch (ex) {
@@ -604,6 +852,7 @@ class AvailabilitySync {
return seasonExists;
}
// Plex
private async mediaExistsInPlex(
media: Media,
is4k: boolean
@@ -719,6 +968,123 @@ class AvailabilitySync {
return seasonExistsInPlex;
}
// Jellyfin
private async mediaExistsInJellyfin(
media: Media,
is4k: boolean
): Promise<{ existsInJellyfin: boolean; seasonsMap?: Map<number, boolean> }> {
const ratingKey = media.jellyfinMediaId;
const ratingKey4k = media.jellyfinMediaId4k;
let existsInJellyfin = false;
let preventSeasonSearch = false;
// Check each jellyfin instance to see if the media still exists
// If found, we will assume the media exists and prevent removal
// We can use the cache we built when we fetched the series with mediaExistsInJellyfin
try {
let jellyfinMedia: JellyfinLibraryItem | undefined;
if (ratingKey && !is4k) {
jellyfinMedia = await this.jellyfinClient?.getItemData(ratingKey);
if (media.mediaType === 'tv' && jellyfinMedia !== undefined) {
this.jellyfinSeasonsCache[ratingKey] =
await this.jellyfinClient?.getSeasons(ratingKey);
}
}
if (ratingKey4k && is4k) {
jellyfinMedia = await this.jellyfinClient?.getItemData(ratingKey4k);
if (media.mediaType === 'tv' && jellyfinMedia !== undefined) {
this.jellyfinSeasonsCache[ratingKey4k] =
await this.jellyfinClient?.getSeasons(ratingKey4k);
}
}
if (jellyfinMedia) {
existsInJellyfin = true;
}
} catch (ex) {
if (!ex.message.includes('404' || '500')) {
existsInJellyfin = false;
preventSeasonSearch = true;
logger.debug(
`Failure retrieving the ${is4k ? '4K' : 'non-4K'} ${
media.mediaType === 'tv' ? 'show' : 'movie'
} [TMDB ID ${media.tmdbId}] from Jellyfin.`,
{
errorMessage: ex.message,
label: 'AvailabilitySync',
}
);
}
}
// Here we check each season in jellyfin for availability
// If the API returns an error other than a 404,
// we will have to prevent the season check from happening
if (media.mediaType === 'tv') {
const seasonsMap: Map<number, boolean> = new Map();
if (!preventSeasonSearch) {
const filteredSeasons = media.seasons.filter(
(season) =>
season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||
season[is4k ? 'status4k' : 'status'] ===
MediaStatus.PARTIALLY_AVAILABLE
);
for (const season of filteredSeasons) {
const seasonExists = await this.seasonExistsInJellyfin(
media,
season,
is4k
);
if (seasonExists) {
seasonsMap.set(season.seasonNumber, true);
}
}
}
return { existsInJellyfin, seasonsMap };
}
return { existsInJellyfin };
}
private async seasonExistsInJellyfin(
media: Media,
season: Season,
is4k: boolean
): Promise<boolean> {
const ratingKey = media.jellyfinMediaId;
const ratingKey4k = media.jellyfinMediaId4k;
let seasonExistsInJellyfin = false;
// Check each jellyfin instance to see if the season exists
let jellyfinSeasons: JellyfinLibraryItem[] | undefined;
if (ratingKey && !is4k) {
jellyfinSeasons = this.jellyfinSeasonsCache[ratingKey];
}
if (ratingKey4k && is4k) {
jellyfinSeasons = this.jellyfinSeasonsCache[ratingKey4k];
}
const seasonIsAvailable = jellyfinSeasons?.find(
(jellyfinSeason) => jellyfinSeason.IndexNumber === season.seasonNumber
);
if (seasonIsAvailable) {
seasonExistsInJellyfin = true;
}
return seasonExistsInJellyfin;
}
}
const availabilitySync = new AvailabilitySync();

View File

@@ -26,7 +26,7 @@ interface SyncStatus {
libraries: Library[];
}
class JobJellyfinSync {
class JellyfinScanner {
private sessionId: string;
private tmdb: TheMovieDb;
private jfClient: JellyfinAPI;
@@ -62,7 +62,7 @@ class JobJellyfinSync {
const metadata = await this.jfClient.getItemData(jellyfinitem.Id);
const newMedia = new Media();
if (!metadata.Id) {
if (!metadata?.Id) {
logger.debug('No Id metadata for this title. Skipping', {
label: 'Plex Sync',
ratingKey: jellyfinitem.Id,
@@ -168,9 +168,9 @@ class JobJellyfinSync {
newMedia.jellyfinMediaId =
hasOtherResolution || (!this.enable4kMovie && has4k)
? metadata.Id
: undefined;
: null;
newMedia.jellyfinMediaId4k =
has4k && this.enable4kMovie ? metadata.Id : undefined;
has4k && this.enable4kMovie ? metadata.Id : null;
await mediaRepository.save(newMedia);
this.log(`Saved ${metadata.Name}`);
}
@@ -197,6 +197,14 @@ class JobJellyfinSync {
jellyfinitem.SeriesId ?? jellyfinitem.SeasonId ?? jellyfinitem.Id;
const metadata = await this.jfClient.getItemData(Id);
if (!metadata?.Id) {
logger.debug('No Id metadata for this title. Skipping', {
label: 'Plex Sync',
ratingKey: jellyfinitem.Id,
});
return;
}
if (metadata.ProviderIds.Tvdb) {
tvShow = await this.tmdb.getShowByTvdbId({
tvdbId: Number(metadata.ProviderIds.Tvdb),
@@ -275,7 +283,7 @@ class JobJellyfinSync {
episode.Id
);
ExtendedEpisodeData.MediaSources?.some((MediaSource) => {
ExtendedEpisodeData?.MediaSources?.some((MediaSource) => {
return MediaSource.MediaStreams.some((MediaStream) => {
if (MediaStream.Type === 'Video') {
if ((MediaStream.Width ?? 0) >= 2000) {
@@ -453,8 +461,9 @@ class JobJellyfinSync {
tmdbId: tvShow.id,
tvdbId: tvShow.external_ids.tvdb_id,
mediaAddedAt: new Date(metadata.DateCreated ?? ''),
jellyfinMediaId: Id,
jellyfinMediaId4k: Id,
jellyfinMediaId: isAllStandardSeasons ? Id : null,
jellyfinMediaId4k:
isAll4kSeasons && this.enable4kShow ? Id : null,
status: isAllStandardSeasons
? MediaStatus.AVAILABLE
: newSeasons.some(
@@ -675,7 +684,7 @@ class JobJellyfinSync {
}
}
export const jobJellyfinFullSync = new JobJellyfinSync();
export const jobJellyfinRecentSync = new JobJellyfinSync({
export const jellyfinFullScanner = new JellyfinScanner();
export const jellyfinRecentScanner = new JellyfinScanner({
isRecentOnly: true,
});

View File

@@ -40,6 +40,7 @@ export interface JellyfinSettings {
name: string;
hostname: string;
externalHostname?: string;
jellyfinForgotPasswordUrl?: string;
libraries: Library[];
serverId: string;
}
@@ -130,6 +131,8 @@ interface FullPublicSettings extends PublicSettings {
originalLanguage: string;
mediaServerType: number;
jellyfinHost?: string;
jellyfinExternalHost?: string;
jellyfinForgotPasswordUrl?: string;
jellyfinServerName?: string;
partialRequestsEnabled: boolean;
cacheImages: boolean;
@@ -330,6 +333,7 @@ class Settings {
name: '',
hostname: '',
externalHostname: '',
jellyfinForgotPasswordUrl: '',
libraries: [],
serverId: '',
},
@@ -533,6 +537,7 @@ class Settings {
applicationUrl: this.data.main.applicationUrl,
hideAvailable: this.data.main.hideAvailable,
localLogin: this.data.main.localLogin,
jellyfinForgotPasswordUrl: this.data.jellyfin.jellyfinForgotPasswordUrl,
movie4kEnabled: this.data.radarr.some(
(radarr) => radarr.is4k && radarr.isDefault
),
@@ -543,6 +548,7 @@ class Settings {
originalLanguage: this.data.main.originalLanguage,
mediaServerType: this.main.mediaServerType,
jellyfinHost: this.jellyfin.hostname,
jellyfinExternalHost: this.jellyfin.externalHostname,
partialRequestsEnabled: this.data.main.partialRequestsEnabled,
cacheImages: this.data.main.cacheImages,
vapidPublic: this.vapidPublic,

View File

@@ -11,6 +11,7 @@ import logger from '@server/logger';
import { isAuthenticated } from '@server/middleware/auth';
import * as EmailValidator from 'email-validator';
import { Router } from 'express';
import gravatarUrl from 'gravatar-url';
const authRoutes = Router();
@@ -274,24 +275,87 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
where: { jellyfinUserId: account.User.Id },
});
if (user) {
if (!user && !(await userRepository.count())) {
// Check if user is admin on jellyfin
if (account.User.Policy.IsAdministrator === false) {
throw new Error('not_admin');
}
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating initial admin user for Overseerr',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
// User doesn't exist, and there are no users in the database, we'll create the user
// with admin permission
settings.main.mediaServerType = MediaServerType.JELLYFIN;
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: Permission.ADMIN,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: gravatarUrl(body.email ?? '', { default: 'mm', size: 200 }),
userType: UserType.JELLYFIN,
});
settings.jellyfin.hostname = body.hostname ?? '';
settings.jellyfin.serverId = account.User.ServerId;
settings.save();
startJobs();
await userRepository.save(user);
}
// User already exists, let's update their information
else if (body.username === user?.jellyfinUsername) {
logger.info(
`Found matching ${
settings.main.mediaServerType === MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby'
} user; updating user with ${
settings.main.mediaServerType === MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby'
}`,
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
// Let's check if their authtoken is up to date
if (user.jellyfinAuthToken !== account.AccessToken) {
user.jellyfinAuthToken = account.AccessToken;
}
// Update the users avatar with their jellyfin profile pic (incase it changed)
if (account.User.PrimaryImageTag) {
user.avatar = `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`;
} else {
user.avatar = '/os_logo_square.png';
user.avatar = gravatarUrl(user.email, {
default: 'mm',
size: 200,
});
}
user.jellyfinUsername = account.User.Name;
if (user.username === account.User.Name) {
user.username = '';
}
// TODO: If JELLYFIN_TYPE is set to 'emby' then set mediaServerType to EMBY
// if (process.env.JELLYFIN_TYPE === 'emby') {
// settings.main.mediaServerType = MediaServerType.EMBY;
// settings.save();
// }
await userRepository.save(user);
} else if (!settings.main.newPlexLogin) {
logger.warn(
@@ -307,69 +371,38 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
status: 403,
message: 'Access denied.',
});
} else {
// Here we check if it's the first user. If it is, we create the user with no check
// and give them admin permissions
const totalUsers = await userRepository.count();
if (totalUsers === 0) {
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating initial admin user for Overseerr',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
user = new User({
email: body.email,
} else if (!user) {
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating new Overseerr user',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: Permission.ADMIN,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
userType: UserType.JELLYFIN,
});
await userRepository.save(user);
//Update hostname in settings if it doesn't exist (initial configuration)
//Also set mediaservertype to JELLYFIN
if (settings.jellyfin.hostname === '') {
settings.main.mediaServerType = MediaServerType.JELLYFIN;
settings.jellyfin.hostname = body.hostname ?? '';
settings.jellyfin.serverId = account.User.ServerId;
settings.save();
startJobs();
}
);
if (!body.email) {
throw new Error('add_email');
}
if (!user) {
if (!body.email) {
throw new Error('add_email');
}
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: settings.main.defaultPermissions,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
userType: UserType.JELLYFIN,
});
//initialize Jellyfin/Emby users with local login
const passedExplicitPassword =
body.password && body.password.length > 0;
if (passedExplicitPassword) {
await user.setPassword(body.password ?? '');
}
await userRepository.save(user);
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: settings.main.defaultPermissions,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: gravatarUrl(body.email, { default: 'mm', size: 200 }),
userType: UserType.JELLYFIN,
});
//initialize Jellyfin/Emby users with local login
const passedExplicitPassword = body.password && body.password.length > 0;
if (passedExplicitPassword) {
await user.setPassword(body.password ?? '');
}
await userRepository.save(user);
}
// Set logged in session
@@ -395,11 +428,21 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
status: 401,
message: 'Unauthorized',
});
} else if (e.message === 'not_admin') {
return next({
status: 403,
message: 'CREDENTIAL_ERROR_NOT_ADMIN',
});
} else if (e.message === 'add_email') {
return next({
status: 406,
message: 'CREDENTIAL_ERROR_ADD_EMAIL',
});
} else if (e.message === 'select_server_type') {
return next({
status: 406,
message: 'CREDENTIAL_ERROR_NO_SERVER_TYPE',
});
} else {
logger.error(e.message, { label: 'Auth' });
return next({

View File

@@ -848,7 +848,7 @@ discoverRoutes.get<Record<string, unknown>, WatchlistResponse>(
if (total) {
return res.json({
page: page,
totalPages: total / itemsPerPage,
totalPages: Math.ceil(total / itemsPerPage),
totalResults: total,
results: result,
});

View File

@@ -12,12 +12,12 @@ import type {
LogsResultsResponse,
SettingsAboutResponse,
} from '@server/interfaces/api/settingsInterfaces';
import { jobJellyfinFullSync } from '@server/job/jellyfinsync';
import { scheduledJobs } from '@server/job/schedule';
import type { AvailableCacheIds } from '@server/lib/cache';
import cacheManager from '@server/lib/cache';
import ImageProxy from '@server/lib/imageproxy';
import { Permission } from '@server/lib/permissions';
import { jellyfinFullScanner } from '@server/lib/scanners/jellyfin';
import { plexFullScanner } from '@server/lib/scanners/plex';
import type { JobId, Library, MainSettings } from '@server/lib/settings';
import { getSettings } from '@server/lib/settings';
@@ -29,6 +29,7 @@ import { getAppVersion } from '@server/utils/appVersion';
import { Router } from 'express';
import rateLimit from 'express-rate-limit';
import fs from 'fs';
import gravatarUrl from 'gravatar-url';
import { escapeRegExp, merge, omit, set, sortBy } from 'lodash';
import { rescheduleJob } from 'node-schedule';
import path from 'path';
@@ -337,7 +338,7 @@ settingsRoutes.get('/jellyfin/users', async (req, res) => {
id: user.Id,
thumb: user.PrimaryImageTag
? `${jellyfinHost}/Users/${user.Id}/Images/Primary/?tag=${user.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
: gravatarUrl(user.Name, { default: 'mm', size: 200 }),
email: user.Name,
}));
@@ -345,16 +346,16 @@ settingsRoutes.get('/jellyfin/users', async (req, res) => {
});
settingsRoutes.get('/jellyfin/sync', (_req, res) => {
return res.status(200).json(jobJellyfinFullSync.status());
return res.status(200).json(jellyfinFullScanner.status());
});
settingsRoutes.post('/jellyfin/sync', (req, res) => {
if (req.body.cancel) {
jobJellyfinFullSync.cancel();
jellyfinFullScanner.cancel();
} else if (req.body.start) {
jobJellyfinFullSync.run();
jellyfinFullScanner.run();
}
return res.status(200).json(jobJellyfinFullSync.status());
return res.status(200).json(jellyfinFullScanner.status());
});
settingsRoutes.get('/tautulli', (_req, res) => {
const settings = getSettings();

View File

@@ -537,7 +537,10 @@ router.post(
permissions: settings.main.defaultPermissions,
avatar: jellyfinUser?.PrimaryImageTag
? `${jellyfinHost}/Users/${jellyfinUser.Id}/Images/Primary/?tag=${jellyfinUser.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
: gravatarUrl(jellyfinUser?.Name ?? '', {
default: 'mm',
size: 200,
}),
userType: UserType.JELLYFIN,
});
@@ -717,29 +720,31 @@ router.get<{ id: string }, WatchlistResponse>(
const user = await getRepository(User).findOneOrFail({
where: { id: Number(req.params.id) },
select: { id: true, plexToken: true },
select: ['id', 'plexToken'],
});
if (!user?.plexToken) {
if (user) {
const [result, total] = await getRepository(Watchlist).findAndCount({
where: { requestedBy: { id: user?.id } },
relations: { requestedBy: true },
// loadRelationIds: true,
take: itemsPerPage,
skip: offset,
if (user) {
const [result, total] = await getRepository(Watchlist).findAndCount({
where: { requestedBy: { id: user?.id } },
relations: {
/*requestedBy: true,media:true*/
},
// loadRelationIds: true,
take: itemsPerPage,
skip: offset,
});
if (total) {
return res.json({
page: page,
totalPages: Math.ceil(total / itemsPerPage),
totalResults: total,
results: result,
});
if (total) {
return res.json({
page: page,
totalPages: total / itemsPerPage,
totalResults: total,
results: result,
});
}
}
}
// We will just return an empty array if the user has no Plex token
// We will just return an empty array if the user has no Plex token
if (!user.plexToken) {
return res.json({
page: 1,
totalPages: 1,

View File

@@ -6,7 +6,7 @@ description: >
Jellyseerr is a free and open source software application for managing requests for your media library.
It is a a fork of Overseerr built to bring support for & focusing mainly on Jellyfin & Emby media servers!
It integrates with your existing services such as Sonarr, Radarr, and Jellyfin/Emby/Plex.
base: core18
base: core20
confinement: strict
architectures:
@@ -16,12 +16,12 @@ architectures:
parts:
jellyseerr:
plugin: nodejs
nodejs-version: '18.18.2'
nodejs-package-manager: 'yarn'
nodejs-yarn-version: v1.22.19
plugin: nil
build-packages:
- git
- ca-certificates
- curl
- gnupg
- on arm64:
- build-essential
- automake
@@ -65,13 +65,30 @@ parts:
snapcraftctl set-version "$SNAP_VERSION"
snapcraftctl set-grade "$GRADE"
build-environment:
- PATH: '$SNAPCRAFT_PART_BUILD/node_modules/.bin:$SNAPCRAFT_PART_BUILD/../npm/bin:$PATH'
- PATH: '$SNAPCRAFT_PART_BUILD/node_modules/.bin:$PATH'
- CYPRESS_INSTALL_BINARY: '0'
override-build: |
set -e
# Install necessary packages
mkdir -p /etc/apt/keyrings
# Add Node.js repository key
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
# Set Node.js version
NODE_MAJOR=18
# Add Node.js repository to sources list
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
# Update package sources and install Node.js
apt-get update
apt-get install nodejs -y
# Install Yarn
npm install -g yarn
# Set COMMIT_TAG before the build begins
export COMMIT_TAG=$(cat $SNAPCRAFT_PART_BUILD/commit.txt)
snapcraftctl build
yarn install --frozen-lockfile --network-timeout 1000000
yarn build
# Copy files needed for staging
cp $SNAPCRAFT_PART_BUILD/committag.json $SNAPCRAFT_PART_INSTALL/
@@ -79,7 +96,7 @@ parts:
cp -R $SNAPCRAFT_PART_BUILD/dist $SNAPCRAFT_PART_INSTALL/
cp -R $SNAPCRAFT_PART_BUILD/node_modules $SNAPCRAFT_PART_INSTALL/
# Remove .github and gitbook as it will fail snap lint
rm -rf $SNAPCRAFT_PART_INSTALL/.github && rm $SNAPCRAFT_PART_INSTALL/.gitbook.yaml
rm -rf $SNAPCRAFT_PART_INSTALL/.github
stage-packages:
- on armhf:
- libatomic1

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -19,6 +19,7 @@ type ListViewProps = {
isLoading?: boolean;
isReachingEnd?: boolean;
onScrollBottom: () => void;
mutateParent?: () => void;
};
const ListView = ({
@@ -28,6 +29,7 @@ const ListView = ({
onScrollBottom,
isReachingEnd,
plexItems,
mutateParent,
}: ListViewProps) => {
const intl = useIntl();
useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd);
@@ -46,7 +48,9 @@ const ListView = ({
id={title.tmdbId}
tmdbId={title.tmdbId}
type={title.mediaType}
isAddedToWatchlist={true}
canExpand
mutateParent={mutateParent}
/>
</li>
);

View File

@@ -30,6 +30,7 @@ const DiscoverWatchlist = () => {
titles,
fetchMore,
error,
mutate,
} = useDiscover<WatchlistItem>(
`/api/v1/${
router.pathname.startsWith('/profile')
@@ -76,6 +77,7 @@ const DiscoverWatchlist = () => {
}
isReachingEnd={isReachingEnd}
onScrollBottom={fetchMore}
mutateParent={mutate}
/>
</>
);

View File

@@ -1,6 +1,7 @@
import EmbyLogo from '@app/assets/services/emby.svg';
import ImdbLogo from '@app/assets/services/imdb.svg';
import JellyfinLogo from '@app/assets/services/jellyfin.svg';
import LetterboxdLogo from '@app/assets/services/letterboxd.svg';
import PlexLogo from '@app/assets/services/plex.svg';
import RTLogo from '@app/assets/services/rt.svg';
import TmdbLogo from '@app/assets/services/tmdb.svg';
@@ -103,6 +104,16 @@ const ExternalLinkBlock = ({
<TraktLogo />
</a>
)}
{tmdbId && mediaType === MediaType.MOVIE && (
<a
href={`https://letterboxd.com/tmdb/${tmdbId}`}
className="w-8 opacity-50 transition duration-300 hover:opacity-100"
target="_blank"
rel="noreferrer"
>
<LetterboxdLogo />
</a>
)}
</div>
);
};

View File

@@ -10,8 +10,8 @@ import { defineMessages, useIntl } from 'react-intl';
import useSWR from 'swr';
const messages = defineMessages({
streamdevelop: 'Overseerr Develop',
streamstable: 'Overseerr Stable',
streamdevelop: 'Jellyseerr Develop',
streamstable: 'Jellyseerr Stable',
outofdate: 'Out of Date',
commitsbehind:
'{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind',

View File

@@ -24,6 +24,7 @@ const messages = defineMessages({
validationusernamerequired: 'Username required',
validationpasswordrequired: 'Password required',
loginerror: 'Something went wrong while trying to sign in.',
adminerror: 'You must use an admin account to sign in.',
credentialerror: 'The username or password is incorrect.',
signingin: 'Signing in…',
signin: 'Sign In',
@@ -67,6 +68,7 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
),
password: Yup.string(),
});
const mediaServerFormatValues = {
mediaServerName:
publicRuntimeConfig.JELLYFIN_TYPE == 'emby' ? 'Emby' : 'Jellyfin',
@@ -93,6 +95,8 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
intl.formatMessage(
e.message == 'Request failed with status code 401'
? messages.credentialerror
: e.message == 'Request failed with status code 403'
? messages.adminerror
: messages.loginerror
),
{
@@ -218,6 +222,11 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
),
password: Yup.string(),
});
const baseUrl = settings.currentSettings.jellyfinExternalHost
? settings.currentSettings.jellyfinExternalHost
: settings.currentSettings.jellyfinHost;
const jellyfinForgotPasswordUrl =
settings.currentSettings.jellyfinForgotPasswordUrl;
return (
<div>
<Formik
@@ -295,11 +304,13 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
as="a"
buttonType="ghost"
href={
process.env.JELLYFIN_TYPE == 'emby'
? settings.currentSettings.jellyfinHost +
'/web/index.html#!/startup/forgotpassword.html'
: settings.currentSettings.jellyfinHost +
'/web/index.html#!/forgotpassword.html'
jellyfinForgotPasswordUrl
? `${jellyfinForgotPasswordUrl}`
: `${baseUrl}/web/index.html#!/${
process.env.JELLYFIN_TYPE === 'emby'
? 'startup/'
: ''
}forgotpassword.html`
}
>
{intl.formatMessage(messages.forgotpassword)}

View File

@@ -1,7 +1,9 @@
import type { PermissionItem } from '@app/components/PermissionOption';
import PermissionOption from '@app/components/PermissionOption';
import useSettings from '@app/hooks/useSettings';
import type { User } from '@app/hooks/useUser';
import { Permission } from '@app/hooks/useUser';
import { MediaServerType } from '@server/constants/server';
import { defineMessages, useIntl } from 'react-intl';
export const messages = defineMessages({
@@ -72,9 +74,9 @@ export const messages = defineMessages({
viewrecent: 'View Recently Added',
viewrecentDescription:
'Grant permission to view the list of recently added media.',
viewwatchlists: 'View Plex Watchlists',
viewwatchlists: 'View {mediaServerName} Watchlists',
viewwatchlistsDescription:
"Grant permission to view other users' Plex Watchlists.",
"Grant permission to view other users' {mediaServerName} Watchlists.",
});
interface PermissionEditProps {
@@ -91,6 +93,7 @@ export const PermissionEdit = ({
onUpdate,
}: PermissionEditProps) => {
const intl = useIntl();
const settings = useSettings();
const permissionList: PermissionItem[] = [
{
@@ -131,8 +134,24 @@ export const PermissionEdit = ({
},
{
id: 'viewwatchlists',
name: intl.formatMessage(messages.viewwatchlists),
description: intl.formatMessage(messages.viewwatchlistsDescription),
name: intl.formatMessage(messages.viewwatchlists, {
mediaServerName:
settings.currentSettings.mediaServerType === MediaServerType.PLEX
? 'Plex'
: settings.currentSettings.mediaServerType ===
MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby',
}),
description: intl.formatMessage(messages.viewwatchlistsDescription, {
mediaServerName:
settings.currentSettings.mediaServerType === MediaServerType.PLEX
? 'Plex'
: settings.currentSettings.mediaServerType ===
MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby',
}),
permission: Permission.WATCHLIST_VIEW,
},
],

View File

@@ -16,7 +16,7 @@ const messages = defineMessages({
agentenabled: 'Enable Agent',
accessToken: 'Application API Token',
accessTokenTip:
'<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Overseerr',
'<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Jellyseerr',
userToken: 'User or Group Key',
userTokenTip:
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',

View File

@@ -19,7 +19,7 @@ const messages = defineMessages({
'Allow users to also start a chat with your bot and configure their own notifications',
botAPI: 'Bot Authorization Token',
botApiTip:
'<CreateBotLink>Create a bot</CreateBotLink> for use with Overseerr',
'<CreateBotLink>Create a bot</CreateBotLink> for use with Jellyseerr',
chatId: 'Chat ID',
chatIdTip:
'Start a chat with your bot, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command',

View File

@@ -18,7 +18,7 @@ const messages = defineMessages({
toastWebPushTestSuccess: 'Web push test notification sent!',
toastWebPushTestFailed: 'Web push test notification failed to send.',
httpsRequirement:
'In order to receive web push notifications, Overseerr must be served over HTTPS.',
'In order to receive web push notifications, Jellyseerr must be served over HTTPS.',
});
const NotificationsWebPush = () => {

View File

@@ -16,7 +16,7 @@ import useSWR from 'swr';
const messages = defineMessages({
about: 'About',
overseerrinformation: 'About Overseerr',
overseerrinformation: 'About Jellyseerr',
version: 'Version',
totalmedia: 'Total Media',
totalrequests: 'Total Requests',
@@ -25,6 +25,7 @@ const messages = defineMessages({
timezone: 'Time Zone',
appDataPath: 'Data Directory',
supportoverseerr: 'Support Overseerr',
supportjellyseerr: 'Support Jellyseerr',
helppaycoffee: 'Help Pay for Coffee',
documentation: 'Documentation',
preferredmethod: 'Preferred',
@@ -33,7 +34,7 @@ const messages = defineMessages({
betawarning:
'This is BETA software. Features may be broken and/or unstable. Please report any issues on GitHub!',
runningDevelop:
'You are running the <code>develop</code> branch of Overseerr, which is only recommended for those contributing to development or assisting with bleeding-edge testing.',
'You are running the <code>develop</code> branch of Jellyseerr, which is only recommended for those contributing to development or assisting with bleeding-edge testing.',
});
const SettingsAbout = () => {
@@ -187,6 +188,54 @@ const SettingsAbout = () => {
</List.Item>
</List>
</div>
<div className="section">
<List title={intl.formatMessage(messages.supportoverseerr)}>
<List.Item
title={`${intl.formatMessage(messages.helppaycoffee)} ☕️`}
>
<a
href="https://github.com/sponsors/sct"
target="_blank"
rel="noreferrer"
className="text-indigo-500 transition duration-300 hover:underline"
>
https://github.com/sponsors/sct
</a>
<Badge className="ml-2">
{intl.formatMessage(messages.preferredmethod)}
</Badge>
</List.Item>
<List.Item title="">
<a
href="https://patreon.com/overseerr"
target="_blank"
rel="noreferrer"
className="text-indigo-500 transition duration-300 hover:underline"
>
https://patreon.com/overseerr
</a>
</List.Item>
</List>
</div>
<div className="section">
<List title={intl.formatMessage(messages.supportjellyseerr)}>
<List.Item
title={`${intl.formatMessage(messages.helppaycoffee)} ☕️`}
>
<a
href="https://www.buymeacoffee.com/fallen.bagel"
target="_blank"
rel="noreferrer"
className="text-indigo-500 transition duration-300 hover:underline"
>
https://www.buymeacoffee.com/fallen.bagel
</a>
<Badge className="ml-2">
{intl.formatMessage(messages.preferredmethod)}
</Badge>
</List.Item>
</List>
</div>
<div className="section">
<Releases currentVersion={data.version} />
</div>

View File

@@ -9,7 +9,7 @@ const messages = defineMessages({
experimentalTooltip:
'Enabling this setting may result in unexpected application behavior',
restartrequiredTooltip:
'Overseerr must be restarted for changes to this setting to take effect',
'Jellyseerr must be restarted for changes to this setting to take effect',
});
const SettingsBadge = ({

View File

@@ -30,9 +30,10 @@ const messages = defineMessages({
jellyfinSettingsSuccess: '{mediaServerName} settings saved successfully!',
jellyfinSettings: '{mediaServerName} Settings',
jellyfinSettingsDescription:
'Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL.',
'Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL. A custom password reset URL can also be set for {mediaServerName} login, in case you would like to redirect to a different password reset page.',
externalUrl: 'External URL',
internalUrl: 'Internal URL',
jellyfinForgotPasswordUrl: 'Forgot Password URL',
validationUrl: 'You must provide a valid URL',
syncing: 'Syncing',
syncJellyfin: 'Sync Libraries',
@@ -94,6 +95,10 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
/^(https?:\/\/)?(?:[\w-]+\.)*[\w-]+(?::\d{2,5})?(?:\/[\w-]+)*(?:\/)?$/gm,
intl.formatMessage(messages.validationUrl)
),
jellyfinForgotPasswordUrl: Yup.string().matches(
/^(https?:\/\/)?(?:[\w-]+\.)*[\w-]+(?::\d{2,5})?(?:\/[\w-]+)*(?:\/)?$/gm,
intl.formatMessage(messages.validationUrl)
),
});
const activeLibraries =
@@ -353,6 +358,7 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
initialValues={{
jellyfinInternalUrl: data?.hostname || '',
jellyfinExternalUrl: data?.externalHostname || '',
jellyfinForgotPasswordUrl: data?.jellyfinForgotPasswordUrl || '',
}}
validationSchema={JellyfinSettingsSchema}
onSubmit={async (values) => {
@@ -360,6 +366,7 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
await axios.post('/api/v1/settings/jellyfin', {
hostname: values.jellyfinInternalUrl,
externalHostname: values.jellyfinExternalUrl,
jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,
} as JellyfinSettings);
addToast(
@@ -437,6 +444,30 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
)}
</div>
</div>
<div className="form-row">
<label
htmlFor="jellyfinForgotPasswordUrl"
className="text-label"
>
{intl.formatMessage(messages.jellyfinForgotPasswordUrl)}
</label>
<div className="form-input-area">
<div className="form-input-field">
<Field
type="text"
inputMode="url"
id="jellyfinForgotPasswordUrl"
name="jellyfinForgotPasswordUrl"
/>
</div>
{errors.jellyfinForgotPasswordUrl &&
touched.jellyfinForgotPasswordUrl && (
<div className="error">
{errors.jellyfinForgotPasswordUrl}
</div>
)}
</div>
</div>
<div className="actions">
<div className="flex justify-end">
<span className="ml-3 inline-flex rounded-md shadow-sm">

View File

@@ -30,7 +30,7 @@ const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
jobsandcache: 'Jobs & Cache',
jobs: 'Jobs',
jobsDescription:
'Overseerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.',
'Jellyseerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.',
jobname: 'Job Name',
jobtype: 'Type',
nextexecution: 'Next Execution',
@@ -42,7 +42,7 @@ const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
command: 'Command',
cache: 'Cache',
cacheDescription:
'Overseerr caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls.',
'Jellyseerr caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls.',
cacheflushed: '{cachename} cache flushed.',
cachename: 'Cache Name',
cachehits: 'Hits',
@@ -76,7 +76,7 @@ const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
'Every {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}',
imagecache: 'Image Cache',
imagecacheDescription:
'When enabled in settings, Overseerr will proxy and cache images from pre-configured external sources. Cached images are saved into your config folder. You can find the files in <code>{appDataPath}/cache/images</code>.',
'When enabled in settings, Jellyseerr will proxy and cache images from pre-configured external sources. Cached images are saved into your config folder. You can find the files in <code>{appDataPath}/cache/images</code>.',
imagecachecount: 'Images Cached',
imagecachesize: 'Total Cache Size',
});

View File

@@ -27,7 +27,7 @@ const messages = defineMessages({
general: 'General',
generalsettings: 'General Settings',
generalsettingsDescription:
'Configure global and default settings for Overseerr.',
'Configure global and default settings for Jellyseerr.',
apikey: 'API Key',
applicationTitle: 'Application Title',
applicationurl: 'Application URL',
@@ -49,7 +49,7 @@ const messages = defineMessages({
'Cache externally sourced images (requires a significant amount of disk space)',
trustProxy: 'Enable Proxy Support',
trustProxyTip:
'Allow Overseerr to correctly register client IP addresses behind a proxy',
'Allow Jellyseerr to correctly register client IP addresses behind a proxy',
validationApplicationTitle: 'You must provide an application title',
validationApplicationUrl: 'You must provide a valid URL',
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',

View File

@@ -49,12 +49,12 @@ const messages = defineMessages({
enablessl: 'Use SSL',
plexlibraries: 'Plex Libraries',
plexlibrariesDescription:
'The libraries Overseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.',
'The libraries Jellyseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.',
scanning: 'Syncing…',
scan: 'Sync Libraries',
manualscan: 'Manual Library Scan',
manualscanDescription:
"Normally, this will only be run once every 24 hours. Overseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!",
"Normally, this will only be run once every 24 hours. Jellyseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!",
notrunning: 'Not Running',
currentlibrary: 'Current Library: {name}',
librariesRemaining: 'Libraries Remaining: {count}',
@@ -67,7 +67,7 @@ const messages = defineMessages({
'Optionally direct users to the web app on your server instead of the "hosted" web app',
tautulliSettings: 'Tautulli Settings',
tautulliSettingsDescription:
'Optionally configure the settings for your Tautulli server. Overseerr fetches watch history data for your Plex media from Tautulli.',
'Optionally configure the settings for your Tautulli server. Jellyseerr fetches watch history data for your Plex media from Tautulli.',
urlBase: 'URL Base',
tautulliApiKey: 'API Key',
externalUrl: 'External URL',

View File

@@ -23,7 +23,7 @@ const messages = defineMessages({
toastSettingsFailure: 'Something went wrong while saving settings.',
localLogin: 'Enable Local Sign-In',
localLoginTip:
'Allow users to sign in using their email address and password, instead of Plex OAuth',
'Allow users to sign in using their email address and password, instead of {mediaServerName} OAuth',
newPlexLogin: 'Enable New {mediaServerName} Sign-In',
newPlexLoginTip:
'Allow {mediaServerName} users to sign in without first being imported',
@@ -114,7 +114,16 @@ const SettingsUsers = () => {
<label htmlFor="localLogin" className="checkbox-label">
{intl.formatMessage(messages.localLogin)}
<span className="label-tip">
{intl.formatMessage(messages.localLoginTip)}
{intl.formatMessage(messages.localLoginTip, {
mediaServerName:
settings.currentSettings.mediaServerType ===
MediaServerType.PLEX
? 'Plex'
: settings.currentSettings.mediaServerType ===
MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby',
})}
</span>
</label>
<div className="form-input-area">

View File

@@ -1,8 +1,10 @@
import Modal from '@app/components/Common/Modal';
import SensitiveInput from '@app/components/Common/SensitiveInput';
import useSettings from '@app/hooks/useSettings';
import globalMessages from '@app/i18n/globalMessages';
import { Transition } from '@headlessui/react';
import type { SonarrSettings } from '@server/lib/settings';
import { MediaServerType } from '@server/constants/server';
import { type SonarrSettings } from '@server/lib/settings';
import axios from 'axios';
import { Field, Formik } from 'formik';
import { useCallback, useEffect, useRef, useState } from 'react';
@@ -109,6 +111,7 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
const { addToast } = useToasts();
const [isValidated, setIsValidated] = useState(sonarr ? true : false);
const [isTesting, setIsTesting] = useState(false);
const settings = useSettings();
const [testResponse, setTestResponse] = useState<TestResponse>({
profiles: [],
rootFolders: [],
@@ -255,7 +258,9 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
animeTags: sonarr?.animeTags ?? [],
isDefault: sonarr?.isDefault ?? false,
is4k: sonarr?.is4k ?? false,
enableSeasonFolders: sonarr?.enableSeasonFolders ?? false,
enableSeasonFolders:
sonarr?.enableSeasonFolders ??
settings.currentSettings.mediaServerType !== MediaServerType.PLEX,
externalUrl: sonarr?.externalUrl,
syncEnabled: sonarr?.syncEnabled ?? false,
enableSearch: !sonarr?.preventSearch,
@@ -961,11 +966,24 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
>
{intl.formatMessage(messages.seasonfolders)}
</label>
<div className="form-input-area">
<div
className={`form-input-area ${
settings.currentSettings.mediaServerType ===
MediaServerType.JELLYFIN ||
settings.currentSettings.mediaServerType ===
MediaServerType.EMBY
? 'opacity-50'
: 'opacity-100'
}`}
>
<Field
type="checkbox"
id="enableSeasonFolders"
name="enableSeasonFolders"
disabled={
settings.currentSettings.mediaServerType !==
MediaServerType.PLEX
}
/>
</div>
</div>

View File

@@ -12,6 +12,7 @@ export interface TmdbTitleCardProps {
type: 'movie' | 'tv';
canExpand?: boolean;
isAddedToWatchlist?: boolean;
mutateParent?: () => void;
}
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
@@ -25,6 +26,7 @@ const TmdbTitleCard = ({
type,
canExpand,
isAddedToWatchlist = false,
mutateParent,
}: TmdbTitleCardProps) => {
const { hasPermission } = useUser();
@@ -71,6 +73,7 @@ const TmdbTitleCard = ({
year={title.releaseDate}
mediaType={'movie'}
canExpand={canExpand}
mutateParent={mutateParent}
/>
) : (
<TitleCard
@@ -87,6 +90,7 @@ const TmdbTitleCard = ({
year={title.firstAirDate}
mediaType={'tv'}
canExpand={canExpand}
mutateParent={mutateParent}
/>
);
};

View File

@@ -38,6 +38,7 @@ interface TitleCardProps {
canExpand?: boolean;
inProgress?: boolean;
isAddedToWatchlist?: number | boolean;
mutateParent?: () => void;
}
const messages = defineMessages({
@@ -61,6 +62,7 @@ const TitleCard = ({
isAddedToWatchlist = false,
inProgress = false,
canExpand = false,
mutateParent,
}: TitleCardProps) => {
const isTouch = useIsTouch();
const intl = useIntl();
@@ -148,6 +150,9 @@ const TitleCard = ({
} finally {
setIsUpdating(false);
mutate('/api/v1/discover/watchlist');
if (mutateParent) {
mutateParent();
}
setToggleWatchlist((prevState) => !prevState);
}
};

View File

@@ -34,6 +34,7 @@ const messages = defineMessages({
seriesrequest: 'Series Requests',
recentlywatched: 'Recently Watched',
plexwatchlist: 'Plex Watchlist',
localWatchlist: "{username}'s Watchlist",
emptywatchlist:
'Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.',
});
@@ -78,17 +79,17 @@ const UserProfile = () => {
? `/api/v1/user/${user.id}/watch_data`
: null
);
const { data: watchlistItems, error: watchlistError } =
useSWR<WatchlistResponse>(
user?.userType === UserType.PLEX &&
(user.id === currentUser?.id ||
currentHasPermission(
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
{
type: 'or',
}
))
? `/api/v1/user/${user.id}/watchlist`
user?.id === currentUser?.id ||
currentHasPermission(
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
{
type: 'or',
}
)
? `/api/v1/user/${user?.id}/watchlist`
: null,
{
revalidateOnMount: true,
@@ -117,6 +118,13 @@ const UserProfile = () => {
return <Error statusCode={404} />;
}
const watchlistSliderTitle = intl.formatMessage(
user.userType === UserType.PLEX
? messages.plexwatchlist
: messages.localWatchlist,
{ username: user.displayName }
);
return (
<>
<PageTitle title={user.displayName} />
@@ -309,12 +317,11 @@ const UserProfile = () => {
/>
</>
)}
{user.userType === UserType.PLEX &&
(user.id === currentUser?.id ||
currentHasPermission(
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
{ type: 'or' }
)) &&
{(user.id === currentUser?.id ||
currentHasPermission(
[Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],
{ type: 'or' }
)) &&
(!watchlistItems ||
!!watchlistItems.results.length ||
(user.id === currentUser?.id &&
@@ -327,11 +334,11 @@ const UserProfile = () => {
href={
user.id === currentUser?.id
? '/profile/watchlist'
: `/users/${user?.id}/watchlist`
: `/users/${user.id}/watchlist`
}
>
<a className="slider-title">
<span>{intl.formatMessage(messages.plexwatchlist)}</span>
<span>{watchlistSliderTitle}</span>
<ArrowRightCircleIcon />
</a>
</Link>

View File

@@ -25,7 +25,7 @@ export type AvailableLocale =
| 'sq'
| 'sr'
| 'sv'
| 'ua'
| 'uk'
| 'zh-CN'
| 'zh-TW';
@@ -127,8 +127,8 @@ export const availableLanguages: AvailableLanguageObject = {
code: 'ja',
display: '日本語',
},
ua: {
code: 'ua',
uk: {
code: 'uk',
display: 'українська',
},
ko: {

View File

@@ -25,6 +25,7 @@ interface DiscoverResult<T, S> {
error: unknown;
titles: T[];
firstResultData?: BaseSearchResult<T> & S;
mutate?: () => void;
}
const extraEncodes: [RegExp, string][] = [
@@ -54,7 +55,7 @@ const useDiscover = <
{ hideAvailable = true } = {}
): DiscoverResult<T, S> => {
const settings = useSettings();
const { data, error, size, setSize, isValidating } = useSWRInfinite<
const { data, error, size, setSize, isValidating, mutate } = useSWRInfinite<
BaseSearchResult<T> & S
>(
(pageIndex: number, previousPageData) => {
@@ -119,6 +120,7 @@ const useDiscover = <
error,
titles,
firstResultData: data?.[0],
mutate,
};
};

View File

@@ -155,7 +155,7 @@
"components.TvDetails.overview": "Přehled",
"components.TvDetails.cast": "Obsazení",
"components.TvDetails.anime": "Anime",
"components.StatusChacker.reloadJellyseerr": "Znovu načíst",
"components.StatusChacker.reloadOverseerr": "Znovu načíst",
"components.Setup.tip": "Tip",
"components.Setup.setup": "Konfigurace",
"components.Setup.finishing": "Dokončování…",

View File

@@ -724,7 +724,7 @@
"components.StatusBadge.status4k": "4K {status}",
"components.Setup.tip": "Tip",
"components.Setup.welcome": "Velkommen til Jellyseerr",
"components.StatusChacker.reloadJellyseerr": "Genindlæs",
"components.StatusChacker.reloadOverseerr": "Genindlæs",
"components.TvDetails.anime": "Anime",
"components.TvDetails.cast": "Roller",
"components.TvDetails.episodeRuntimeMinutes": "{runtime} minutter",

View File

@@ -162,7 +162,7 @@
"components.ManageSlideOver.playedby": "Abgespielt von",
"components.ManageSlideOver.plays": "<strong>{playCount, number}</strong> {playCount, plural, one {abgespielt} other {abgespielt}}",
"components.ManageSlideOver.tvshow": "Serie",
"components.MediaSlider.ShowMoreCard.seemore": "Mehr anzeigen",
"components.MediaSlider.ShowMoreCard.seemore": "Mehr anschauen",
"components.MovieDetails.MovieCast.fullcast": "Komplette Besetzung",
"components.MovieDetails.MovieCrew.fullcrew": "Komplette Crew",
"components.MovieDetails.budget": "Budget",
@@ -312,14 +312,14 @@
"components.RequestBlock.rootfolder": "Stammordner",
"components.RequestBlock.seasons": "{seasonCount, plural, one {Staffel} other {Staffeln}}",
"components.RequestBlock.server": "Zielserver",
"components.RequestButton.approve4krequests": "Genehmige {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Anfragen}}",
"components.RequestButton.approve4krequests": "Genehmige {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Requests}}",
"components.RequestButton.approverequest": "Anfrage genehmigen",
"components.RequestButton.approverequest4k": "4K Anfrage genehmigen",
"components.RequestButton.approverequests": "Genehmige {requestCount, plural, one {Anfrage} other {{requestCount} Anfragen}}",
"components.RequestButton.decline4krequests": "Lehne {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Anfragen}} ab",
"components.RequestButton.approverequests": "Genehmige {requestCount, plural, one {Anfrage} other {{requestCount} Requests}}",
"components.RequestButton.decline4krequests": "Lehne {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Requests}} ab",
"components.RequestButton.declinerequest": "Anfrage ablehnen",
"components.RequestButton.declinerequest4k": "4K Anfrage ablehnen",
"components.RequestButton.declinerequests": "Lehne {requestCount, plural, one {Anfrage} other {{requestCount} Anfragen}} ab",
"components.RequestButton.declinerequests": "Lehne {requestCount, plural, one {Anfrage} other {{requestCount} Requests}} ab",
"components.RequestButton.requestmore": "Mehr anfragen",
"components.RequestButton.requestmore4k": "Mehr in 4K anfragen",
"components.RequestButton.viewrequest": "Anfrage anzeigen",
@@ -1235,10 +1235,115 @@
"components.Discover.tmdbmoviestreamingservices": "TMDB Film-Streaming-Dienste",
"components.Discover.tmdbtvstreamingservices": "TMDB TV-Streaming-Dienste",
"i18n.collection": "Sammlung",
"components.Discover.FilterSlideover.tmdbuservotecount": "TMDB Kullanıcı Oy Sayısı",
"components.Discover.FilterSlideover.tmdbuservotecount": "Anzahl an TMDB Benutzerbewertungen",
"components.Settings.RadarrModal.tagRequestsInfo": "Füge automatisch ein Tag hinzu mit der ID und dem Namen des anfordernden Nutzers",
"components.MovieDetails.imdbuserscore": "IMDB Nutzer Bewertung",
"components.Settings.SonarrModal.tagRequests": "Tag Anforderungen",
"components.Discover.FilterSlideover.voteCount": "Anzahl Abstimmungen zwischen {minValue} und {maxValue}",
"components.Settings.SonarrModal.tagRequestsInfo": "Füge automatisch einen zusätzlichen Tag mit der ID & Namen des anfordernden Nutzers"
"components.Settings.SonarrModal.tagRequestsInfo": "Füge automatisch einen zusätzlichen Tag mit der ID & Namen des anfordernden Nutzers",
"components.Layout.UserWarnings.passwordRequired": "Ein Passwort ist erforderlich.",
"components.Login.description": "Da du dich zum ersten Mal bei {applicationName} anmeldest, musst du eine gültige E-Mail-Adresse angeben.",
"components.Layout.UserWarnings.emailRequired": "E-Mail ist erforderlich.",
"components.Layout.UserWarnings.emailInvalid": "E-Mail ist nicht valide.",
"components.Login.credentialerror": "Der Benutzername oder das Passwort ist falsch.",
"components.Login.emailtooltip": "Die Adresse muss nicht mit Ihrer {mediaServerName}-Instanz verbunden sein.",
"components.Login.host": "{mediaServerName} URL",
"components.Login.initialsignin": "Verbinde",
"components.Login.initialsigningin": "Verbinden…",
"components.Login.save": "hinzufügen",
"components.Login.saving": "Hinzufügen…",
"components.Login.signinwithjellyfin": "Verwende dein {mediaServerName} Konto",
"components.Login.title": "E-Mail hinzufügen",
"components.Login.username": "Benutzername",
"components.Login.validationEmailFormat": "Ungültige E-Mail",
"components.Login.validationEmailRequired": "Du musst eine E-Mail angeben",
"components.Login.validationemailformat": "Gültige E-Mail erforderlich",
"components.Login.validationhostformat": "Gültige URL erforderlich",
"components.Login.validationhostrequired": "{mediaServerName} URL erforderlich",
"components.Login.validationusernamerequired": "Benutzername erforderlich",
"components.ManageSlideOver.removearr": "Aus {arr} entfernen",
"components.ManageSlideOver.removearr4k": "Aus 4K {arr} entfernen",
"components.MovieDetails.downloadstatus": "Download-Status",
"components.MovieDetails.openradarr4k": "Film in 4K Radarr öffnen",
"components.MovieDetails.play": "Wiedergabe auf {mediaServerName}",
"components.MovieDetails.play4k": "4K abspielen auf {mediaServerName}",
"components.Settings.SonarrModal.animeSeriesType": "Anime-Serien Typ",
"components.Settings.jellyfinSettings": "{mediaServerName} Einstellungen",
"components.Settings.jellyfinSettingsSuccess": "{mediaServerName} Einstellungen erfolgreich gespeichert!",
"components.Settings.jellyfinlibraries": "{mediaServerName} Bibliotheken",
"components.Settings.jellyfinsettings": "{mediaServerName} Einstellungen",
"components.Settings.jellyfinsettingsDescription": "Konfiguriere die Einstellungen für deinen {mediaServerName} Server. {mediaServerName} scannt deine {mediaServerName} Bibliotheken, um zu sehen, welche Inhalte verfügbar sind.",
"components.Settings.manualscanJellyfin": "Manuelles Scannen der Bibliothek",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.Settings.saving": "Speichern…",
"components.Settings.syncing": "Synchronisierung",
"components.Settings.timeout": "Zeitüberschreitung",
"components.Setup.signin": "Anmelden",
"components.Setup.signinWithJellyfin": "Verwende dein {mediaServerName} Konto",
"components.Setup.signinWithPlex": "Verwende dein Plex-Konto",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> Erfolgreich von der Beobachtungsliste entfernt!",
"components.TitleCard.watchlistError": "Etwas ist schief gelaufen, versuche es noch einmal.",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> erfolgreich zur Beobachtungsliste hinzugefügt!",
"components.TvDetails.play": "Wiedergabe auf {mediaServerName}",
"components.TvDetails.play4k": "4K abspielen auf {mediaServerName}",
"components.UserList.importfromJellyfin": "Importieren von {mediaServerName} Benutzern",
"components.UserList.mediaServerUser": "{mediaServerName} Benutzer",
"components.UserList.noJellyfinuserstoimport": "Es gibt keine {mediaServerName} Benutzer zu importieren.",
"components.UserList.userdeleted": "Benutzer erfolgreich gelöscht!",
"components.UserList.userdeleteerror": "Beim Löschen des Benutzers ist etwas schief gelaufen.",
"components.UserList.userlist": "Benutzerliste",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "E-Mail",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "{mediaServerName} Benutzer",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Speichern…",
"components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingssaved": "Web-Push-Benachrichtigungseinstellungen erfolgreich gespeichert!",
"i18n.close": "Schließen",
"i18n.decline": "Ablehnen",
"i18n.declined": "Abgelehnt",
"i18n.delete": "Löschen",
"i18n.deleting": "Löschen…",
"i18n.failed": "Fehlgeschlagen",
"i18n.movies": "Filme",
"i18n.open": "Öffnen",
"i18n.pending": "Ausstehend",
"i18n.processing": "Verarbeitung",
"i18n.request": "Anfrage",
"i18n.requested": "Angefragt",
"i18n.retry": "Wiederholen",
"i18n.tvshows": "Serie",
"i18n.unavailable": "Nicht verfügbar",
"pages.oops": "Ups",
"components.MovieDetails.openradarr": "Film in Radarr öffnen",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Gerätestandard",
"components.Settings.RadarrModal.tagRequests": "Tag-Anfragen",
"components.Settings.SettingsAbout.supportjellyseerr": "Jellyseerr unterstützen",
"components.Settings.internalUrl": "Interne URL",
"components.Settings.jellyfinSettingsDescription": "Konfiguriere optional die internen und externen Endpunkte für deinen {mediaServerName} Server. In den meisten Fällen ist die externe URL eine andere als die interne URL. Für die Anmeldung bei {mediaServerName} kann auch eine benutzerdefinierte URL zum Zurücksetzen des Passworts festgelegt werden, falls du auf eine andere Seite zum Zurücksetzen des Passworts umleiten möchtest.",
"components.Settings.jellyfinSettingsFailure": "Beim Speichern der Einstellungen von {mediaServerName} ist ein Fehler aufgetreten.",
"components.Settings.manualscanDescriptionJellyfin": "Normalerweise wird dieser Vorgang nur einmal alle 24 Stunden durchgeführt. Jellyseerr wird die kürzlich hinzugefügten Bibliotheken deines {mediaServerName} Servers aggressiver überprüfen. Wenn dies das erste Mal ist, dass du Jellyseerr konfigurierst, wird ein einmaliger vollständiger manueller Bibliotheks-Scan empfohlen!",
"components.Settings.save": "Änderungen speichern",
"components.Settings.Notifications.userEmailRequired": "Benutzer-E-Mai",
"components.Settings.Notifications.NotificationsPushover.sound": "Benachrichtigungston",
"components.Settings.SonarrModal.seriesType": "TV-Serie Typ",
"components.Settings.jellyfinlibrariesDescription": "Die Bibliotheken {mediaServerName} werden nach Titeln durchsucht. Klicke auf die Schaltfläche unten, wenn keine Bibliotheken aufgelistet sind.",
"components.UserList.importfromJellyfinerror": "Beim Importieren von {mediaServerName} Benutzern ist etwas schief gelaufen.",
"components.Settings.syncJellyfin": "Bibliotheken synchronisieren",
"components.Setup.configuremediaserver": "Medienserver konfigurieren",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Änderungen speichern",
"i18n.available": "Verfügbar",
"i18n.cancel": "Abbrechen",
"components.TitleCard.addToWatchList": "Zur Beobachtungsliste hinzufügen",
"components.TitleCard.watchlistCancel": "Überwachungsliste für <strong>{title}</strong> abgebrochen.",
"components.UserList.usercreatedsuccess": "Benutzer erfolgreich angelegt!",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Dadurch wird dieser {mediaType} unwiderruflich aus {arr} entfernt, einschließlich aller Dateien.",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} erfolgreich importiert!",
"components.UserList.validationpasswordminchars": "Das Passwort ist zu kurz; es sollte mindestens 8 Zeichen lang sein",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Gerätestandard",
"i18n.approve": "Genehmigen",
"i18n.partiallyavailable": "Teilweise verfügbar",
"components.UserList.newJellyfinsigninenabled": "Die Einstellung <strong>Enable New {mediaServerName} Sign-In</strong> ist derzeit aktiviert. {mediaServerName}-Benutzer mit Bibliothekszugang müssen nicht importiert werden, um sich anmelden zu können.",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Benachrichtigungston",
"components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingsfailed": "Die Einstellungen für Web-Push-Benachrichtigungen konnten nicht gespeichert werden.",
"components.UserProfile.localWatchlist": "Beobachtungsliste von {username}",
"i18n.approved": "Genehmigt",
"pages.returnHome": "Zurück nach Hause"
}

View File

@@ -634,7 +634,7 @@
"components.TvDetails.anime": "Anime",
"components.TvDetails.TvCrew.fullseriescrew": "Όλο το Πλήρωμα της Σειράς",
"components.TvDetails.TvCast.fullseriescast": "Όλοι οι Ηθοποιοί της Σειράς",
"components.StatusChacker.reloadJellyseerr": "Επαναφόρτωση",
"components.StatusChacker.reloadOverseerr": "Επαναφόρτωση",
"components.StatusChacker.newversionavailable": "Ενημέρωση εφαρμογής",
"components.StatusChacker.newversionDescription": "Το Jellyseerr έχει ενημερωθεί! Κάνε κλικ στο παρακάτω κουμπί για να φορτώσει ξανά η σελίδα.",
"components.StatusBadge.status4k": "4K {status}",

View File

@@ -94,7 +94,6 @@
"components.Discover.emptywatchlist": "Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.",
"components.Discover.moviegenres": "Movie Genres",
"components.Discover.networks": "Networks",
"components.Discover.noRequests": "No requests.",
"components.Discover.plexwatchlist": "Your Watchlist",
"components.Discover.popularmovies": "Popular Movies",
"components.Discover.populartv": "Popular Series",
@@ -200,9 +199,9 @@
"components.LanguageSelector.originalLanguageDefault": "All Languages",
"components.Layout.LanguagePicker.displaylanguage": "Display Language",
"components.Layout.SearchInput.searchPlaceholder": "Search Movies & TV",
"components.Layout.Sidebar.dashboard": "Discover",
"components.Layout.Sidebar.browsemovies": "Movies",
"components.Layout.Sidebar.browsetv": "Series",
"components.Layout.Sidebar.dashboard": "Discover",
"components.Layout.Sidebar.issues": "Issues",
"components.Layout.Sidebar.requests": "Requests",
"components.Layout.Sidebar.settings": "Settings",
@@ -221,8 +220,10 @@
"components.Layout.VersionStatus.streamdevelop": "Jellyseerr Develop",
"components.Layout.VersionStatus.streamstable": "Jellyseerr Stable",
"components.Login.credentialerror": "The username or password is incorrect.",
"components.Login.adminerror": "You must use an admin account to sign in.",
"components.Login.description": "Since this is your first time logging into {applicationName}, you are required to add a valid email address.",
"components.Login.email": "Email Address",
"components.Login.emailtooltip": "Address does not need to be associated with your {mediaServerName} instance.",
"components.Login.forgotpassword": "Forgot Password?",
"components.Login.host": "{mediaServerName} URL",
"components.Login.initialsignin": "Connect",
@@ -394,8 +395,8 @@
"components.PermissionEdit.viewrecentDescription": "Grant permission to view the list of recently added media.",
"components.PermissionEdit.viewrequests": "View Requests",
"components.PermissionEdit.viewrequestsDescription": "Grant permission to view media requests submitted by other users.",
"components.PermissionEdit.viewwatchlists": "View Plex Watchlists",
"components.PermissionEdit.viewwatchlistsDescription": "Grant permission to view other users' Plex Watchlists.",
"components.PermissionEdit.viewwatchlists": "View {mediaServerName} Watchlists",
"components.PermissionEdit.viewwatchlistsDescription": "Grant permission to view other users' {mediaServerName} Watchlists.",
"components.PersonDetails.alsoknownas": "Also Known As: {names}",
"components.PersonDetails.appearsin": "Appearances",
"components.PersonDetails.ascharacter": "as {character}",
@@ -751,7 +752,8 @@
"components.Settings.SettingsAbout.overseerrinformation": "About Jellyseerr",
"components.Settings.SettingsAbout.preferredmethod": "Preferred",
"components.Settings.SettingsAbout.runningDevelop": "You are running the <code>develop</code> branch of Jellyseerr, which is only recommended for those contributing to development or assisting with bleeding-edge testing.",
"components.Settings.SettingsAbout.supportoverseerr": "Support Jellyseerr",
"components.Settings.SettingsAbout.supportoverseerr": "Support Overseerr",
"components.Settings.SettingsAbout.supportjellyseerr": "Support Jellyseerr",
"components.Settings.SettingsAbout.timezone": "Time Zone",
"components.Settings.SettingsAbout.totalmedia": "Total Media",
"components.Settings.SettingsAbout.totalrequests": "Total Requests",
@@ -851,7 +853,7 @@
"components.Settings.SettingsUsers.defaultPermissions": "Default Permissions",
"components.Settings.SettingsUsers.defaultPermissionsTip": "Initial permissions assigned to new users",
"components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In",
"components.Settings.SettingsUsers.localLoginTip": "Allow users to sign in using their email address and password, instead of Plex OAuth",
"components.Settings.SettingsUsers.localLoginTip": "Allow users to sign in using their email address and password, instead of {mediaServerName} OAuth",
"components.Settings.SettingsUsers.movieRequestLimitLabel": "Global Movie Request Limit",
"components.Settings.SettingsUsers.newPlexLogin": "Enable New {mediaServerName} Sign-In",
"components.Settings.SettingsUsers.newPlexLoginTip": "Allow {mediaServerName} users to sign in without first being imported",
@@ -937,7 +939,7 @@
"components.Settings.internalUrl": "Internal URL",
"components.Settings.is4k": "4K",
"components.Settings.jellyfinSettings": "{mediaServerName} Settings",
"components.Settings.jellyfinSettingsDescription": "Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL.",
"components.Settings.jellyfinSettingsDescription": "Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL. A custom password reset URL can also be set for {mediaServerName} login, in case you would like to redirect to a different password reset page.",
"components.Settings.jellyfinSettingsFailure": "Something went wrong while saving {mediaServerName} settings.",
"components.Settings.jellyfinSettingsSuccess": "{mediaServerName} settings saved successfully!",
"components.Settings.jellyfinlibraries": "{mediaServerName} Libraries",
@@ -1042,10 +1044,15 @@
"components.StatusChecker.reloadApp": "Reload {applicationTitle}",
"components.StatusChecker.restartRequired": "Server Restart Required",
"components.StatusChecker.restartRequiredDescription": "Please restart the server to apply the updated settings.",
"components.TitleCard.addToWatchList": "Add to watchlist",
"components.TitleCard.cleardata": "Clear Data",
"components.TitleCard.mediaerror": "{mediaType} Not Found",
"components.TitleCard.tmdbid": "TMDB ID",
"components.TitleCard.tvdbid": "TheTVDB ID",
"components.TitleCard.watchlistCancel": "watchlist for <strong>{title}</strong> canceled.",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> Removed from watchlist successfully!",
"components.TitleCard.watchlistError": "Something went wrong try again.",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> added to watchlist successfully!",
"components.TvDetails.Season.noepisodes": "Episode list unavailable.",
"components.TvDetails.Season.somethingwentwrong": "Something went wrong while retrieving season data.",
"components.TvDetails.TvCast.fullseriescast": "Full Series Cast",
@@ -1229,6 +1236,7 @@
"components.UserProfile.UserSettings.unauthorizedDescription": "You do not have permission to modify this user's settings.",
"components.UserProfile.emptywatchlist": "Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.",
"components.UserProfile.limit": "{remaining} of {limit}",
"components.UserProfile.localWatchlist": "{username}'s Watchlist",
"components.UserProfile.movierequests": "Movie Requests",
"components.UserProfile.pastdays": "{type} (past {days} days)",
"components.UserProfile.plexwatchlist": "Plex Watchlist",
@@ -1238,11 +1246,6 @@
"components.UserProfile.seriesrequest": "Series Requests",
"components.UserProfile.totalrequests": "Total Requests",
"components.UserProfile.unlimited": "Unlimited",
"components.TitleCard.addToWatchList": "Add to watchlist",
"components.TitleCard.watchlistCancel": "watchlist for <strong>{title}</strong> canceled.",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> Removed from watchlist successfully!",
"components.TitleCard.watchlistError": "Something went wrong try again.",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> added to watchlist successfully!",
"i18n.advanced": "Advanced",
"i18n.all": "All",
"i18n.approve": "Approve",

View File

@@ -201,7 +201,7 @@
"components.Settings.SonarrModal.animerootfolder": "Carpeta raíz de anime",
"components.Settings.SonarrModal.animequalityprofile": "Perfil de calidad de anime",
"components.Settings.SettingsAbout.timezone": "Zona horaria",
"components.Settings.SettingsAbout.supportoverseerr": "Apoya a Jellyseerr",
"components.Settings.SettingsAbout.supportoverseerr": "Apoya a Overseerr",
"components.Settings.SettingsAbout.helppaycoffee": "Ayúdame invitándome a un café",
"components.Settings.SettingsAbout.Releases.viewongithub": "Ver en GitHub",
"components.Settings.SettingsAbout.Releases.viewchangelog": "Ver registro de cambios",
@@ -299,14 +299,14 @@
"components.RequestButton.viewrequest": "Ver Solicitud",
"components.RequestButton.requestmore4k": "Solicitar más en 4K",
"components.RequestButton.requestmore": "Solicitar más",
"components.RequestButton.declinerequests": "Rechazar {requestCount, plural, one {solicitud} other {{requestCount} solicitudes}}",
"components.RequestButton.declinerequests": "Rechazar {requestCount, plural, one {Request} other {{requestCount} Requests}}",
"components.RequestButton.declinerequest4k": "Rechazar Solicitud 4K",
"components.RequestButton.declinerequest": "Rechazar Solicitud",
"components.RequestButton.decline4krequests": "Rechazar {requestCount, plural, one {solicitud en 4K} other {{requestCount} solicitudes en 4K}}",
"components.RequestButton.approverequests": "Aprobar {requestCount, plural, one {solicitud} other {{requestCount} solicitudes}}",
"components.RequestButton.decline4krequests": "Rechazar {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}",
"components.RequestButton.approverequests": "Aprobar {requestCount, plural, one {Request} other {{requestCount} Requests}}",
"components.RequestButton.approverequest4k": "Aprobar Solicitud 4K",
"components.RequestButton.approverequest": "Aprobar Solicitud",
"components.RequestButton.approve4krequests": "Aprobar {requestCount, plural, one {petición en 4K} other {requestCount} peticiones en 4K}}",
"components.RequestButton.approve4krequests": "Aprobar {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}",
"components.RequestBlock.server": "Servidor de Destino",
"components.RequestBlock.rootfolder": "Carpeta Raíz",
"components.RequestBlock.profilechanged": "Perfil de Calidad",
@@ -656,7 +656,7 @@
"components.QuotaSelector.unlimited": "Ilimitadas",
"components.MovieDetails.originaltitle": "Título Original",
"components.LanguageSelector.originalLanguageDefault": "Todos los Idiomas",
"components.LanguageSelector.languageServerDefault": "({Language}) por defecto",
"components.LanguageSelector.languageServerDefault": "({language}) por defecto",
"components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {cambio} other {cambios}} por detrás",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Tu cuenta no tiene configurada una contraseña actualmente. Configure una contraseña a continuación para habilitar el acceso como \"usuario local\" utilizando tu dirección de email.",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Esta cuenta de usuario no tiene configurada una contraseña actualmente. Configure una contraseña a continuación para habilitar el acceso como \"usuario local\"",
@@ -784,7 +784,7 @@
"components.DownloadBlock.estimatedtime": "Estimación de {time}",
"components.Settings.Notifications.encryptionOpportunisticTls": "Usa siempre STARTTLS",
"components.TvDetails.streamingproviders": "Emisión Actual en",
"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault": "{{Language}} por defecto",
"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault": "({language}) por defecto",
"components.Settings.Notifications.NotificationsWebPush.httpsRequirement": "Para recibir notificaciones web push, Jellyseerr debe servirse mediante HTTPS.",
"components.Settings.Notifications.NotificationsWebhook.validationTypes": "Debes seleccionar, al menos, un tipo de notificación",
"components.Settings.Notifications.validationTypes": "Debes seleccionar, al menos, un tipo de notificación",
@@ -816,10 +816,10 @@
"components.Settings.Notifications.encryptionTip": "Normalmente, TLS Implícito usa el puerto 465 y STARTTLS usa el puerto 587",
"components.UserList.localLoginDisabled": "El ajuste para <strong>Habilitar el Inicio de Sesión Local</strong> está actualmente deshabilitado.",
"components.Settings.SettingsUsers.defaultPermissionsTip": "Permisos iniciales asignados a nuevos usuarios",
"components.Settings.SettingsAbout.runningDevelop": "Estás utilizando la rama de <code>develop</code> de Jellyseerr, la cual solo se recomienda para aquellos que contribuyen al desarrollo o al soporte de las pruebas de nuevos desarrollos.",
"components.Settings.SettingsAbout.runningDevelop": "Estás utilizando la rama de <code>desarrollo</code> de Jellyseerr, la cual solo se recomienda para aquellos que contribuyen al desarrollo o al soporte de las pruebas de nuevos desarrollos.",
"components.StatusBadge.status": "{status}",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes": "Cada {jobScheduleMinutes, plural, one {minuto} other {{jobScheduleMinutes} minutos}}",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "Cada {jobScheduleHours, plural, one {hora} other {{jobScheduleHours} horas}}",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes": "Cada {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "Cada {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}",
"components.Settings.SettingsJobsCache.jobScheduleEditFailed": "Algo fue mal al guardar la tarea programada.",
"components.Settings.SettingsJobsCache.editJobSchedule": "Modificar tarea programada",
"components.Settings.SettingsJobsCache.editJobSchedulePrompt": "Nueva frecuencia",
@@ -848,7 +848,7 @@
"components.IssueDetails.nocomments": "Sin comentarios.",
"components.IssueDetails.openedby": "#{issueId} abierta {relativeTime} por {username}",
"components.IssueDetails.openin4karr": "Abrir en {arr} 4K",
"components.IssueDetails.openinarr": "Abierta en {arr}",
"components.IssueDetails.openinarr": "Abrir en {arr}",
"components.IssueDetails.play4konplex": "Ver en 4K en {mediaServerName}",
"components.IssueDetails.playonplex": "Ver en {mediaServerName}",
"components.IssueDetails.problemepisode": "Episodio Afectado",
@@ -1193,7 +1193,7 @@
"components.RequestList.RequestItem.tvdbid": "Identificador de TheTVDB",
"components.Settings.SettingsJobsCache.image-cache-cleanup": "Limpieza de la caché de imágenes",
"components.Settings.SettingsJobsCache.imagecache": "Caché de imágenes",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "Cada {jobScheduleSeconds, plural, one {segundo} other {{jobScheduleSeconds} segundos}}",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "Cada {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}",
"components.Settings.SettingsJobsCache.availability-sync": "Sincronización de la disponibilidad de medios",
"components.Discover.tmdbmoviestreamingservices": "Servicios de streaming de películas TMDB",
"components.Discover.tmdbtvstreamingservices": "Servicios de TV en streaming TMDB",
@@ -1204,5 +1204,111 @@
"i18n.collection": "Colección",
"components.Settings.RadarrModal.tagRequestsInfo": "Añadir automáticamente una etiqueta adicional con el nombre de usuario y el nombre para mostrar del solicitante",
"components.Settings.SonarrModal.tagRequestsInfo": "Añadir automáticamente una etiqueta adicional con el nombre de usuario y el nombre para mostrar del solicitante",
"components.MovieDetails.imdbuserscore": "Puntuación de los usuarios de IMDB"
"components.MovieDetails.imdbuserscore": "Puntuación de los usuarios de IMDB",
"components.Layout.UserWarnings.passwordRequired": "Se requiere una contraseña.",
"components.Login.credentialerror": "El usuario o contraseña es incorrecto.",
"components.Login.host": "{mediaServerName} URL",
"components.Login.initialsignin": "Conectar",
"components.Login.initialsigningin": "Conectando…",
"components.Login.emailtooltip": "No es necesario asociar la dirección con su instancia de {mediaServerName}.",
"components.Login.saving": "Añadiendo…",
"components.Login.title": "Añadir Email",
"components.Login.username": "Nombre de usuario",
"components.Login.validationEmailFormat": "El email es inválido",
"components.Login.validationEmailRequired": "Debes proporcional un email",
"components.Login.validationemailformat": "Se requiere de un email válido",
"components.Login.validationhostformat": "Se requiere de una URL válida",
"components.Login.validationusernamerequired": "Se requiere un nombre de usuario",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Esto eliminará de manera irreversible esta {mediaType} de {arr}, incluyendo todos los archivos.",
"i18n.open": "Abierto",
"components.MovieDetails.downloadstatus": "Estado de la descarga",
"components.MovieDetails.openradarr": "Abrir Película en Radarr",
"components.MovieDetails.openradarr4k": "Abrir Película 4K en Radarr",
"components.MovieDetails.play": "Reproducir en {mediaServerName}",
"components.MovieDetails.play4k": "Reproducir 4K en {mediaServerName}",
"components.NotificationTypeSelector.issueresolved": "Incidencia Resuelta",
"components.NotificationTypeSelector.userissuecommentDescription": "Notificame cuando haya nuevos comentarios en incidencias que haya abierto.",
"components.NotificationTypeSelector.userissuecreatedDescription": "Notificame cuando otros usuarios reporten incidencias.",
"components.PermissionEdit.viewissues": "Ver incidencias",
"components.PermissionEdit.manageissuesDescription": "Dar permiso para administrar incidencias.",
"components.PermissionEdit.viewissuesDescription": "Dar permiso para ver incidencias reportadas por otros usuarios.",
"components.Settings.Notifications.NotificationsPushover.sound": "Sonido de Notificacion",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Escanear Añadidos Recientemente de Jellyfin",
"components.Settings.SettingsJobsCache.jellyfin-full-scan": "Escaneo Completo de la libreria de Jellyfin",
"components.Settings.jellyfinSettings": "Ajustes de {mediaServerName}",
"components.Settings.jellyfinsettings": "Ajustes de {mediaServerName}",
"components.Settings.jellyfinSettingsFailure": "Algo salió mal al guardar la configuración de {mediaServerName}.",
"components.Settings.jellyfinSettingsSuccess": "¡La configuración de {mediaServerName} se guardó correctamente!",
"components.Settings.jellyfinlibraries": "Bibliotecas {mediaServerName}",
"components.Settings.jellyfinlibrariesDescription": "La biblioteca {mediaServerName} busca títulos. Haga clic en el botón a continuación si no aparece ninguna biblioteca.",
"components.Settings.manualscanDescriptionJellyfin": "Normalmente, esto sólo se ejecutará una vez cada 24 horas. Jellyseerr comprobará de forma más agresiva los añadidos recientemente de su servidor {mediaServerName}. ¡Si es la primera vez que configura Jellyseerr, se recomienda un escaneo manual completo de la biblioteca!",
"components.Settings.save": "Guardar Cambios",
"components.Settings.saving": "Guardando…",
"components.Settings.syncing": "Sincronizando",
"components.Settings.timeout": "Tiempo agotado",
"components.Setup.signinWithPlex": "Usa tu cuenta de Plex",
"components.Setup.configuremediaserver": "Configurar servidor multimedia",
"components.TitleCard.addToWatchList": "Añadir a lista de seguimiento",
"components.TitleCard.watchlistCancel": "Lista de seguimiento para <strong>{title}</strong> cancelada.",
"components.TitleCard.watchlistError": "Algo salió mal, intenta de nuevo.",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> añadido correctamente a la lista de seguimiento!",
"components.TvDetails.play": "Reproducir en {mediaServerName}",
"components.UserList.importfromJellyfin": "Importar Usuarios de {mediaServerName}",
"components.UserList.mediaServerUser": "Usuario de {mediaServerName}",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} importado correctamente!",
"components.UserList.importfromJellyfinerror": "Se produjo un error al importar usuarios de {mediaServerName}.",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Guardar Cambios",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "Email",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Dispositivo Predeterminado",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Sonido de Notificacion",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed": "Fallo al guardar los ajustes de la notificación Pushbullet.",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved": "¡Los ajustes de notificación Pushbullet se han guardado con éxito!",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken": "Token de aplicación API",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey": "Clave de usuario o grupo",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip": "Tu <UsersGroupsLink>identificador de usuario o grupo</UsersGroupsLink> de 30 caracteres",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved": "¡Se han guardado los ajustes de notificación de Pushover!",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip": "<ApplicationRegistrationLink>Registrar una aplicación</ApplicationRegistrationLink> para usar con {applicationTitle}",
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey": "Debes proporcionar una clave de usuario o grupo válida",
"components.Login.validationhostrequired": "{mediaServerName} URL requerida",
"i18n.resolved": "Resuelto",
"components.UserList.importfrommediaserver": "Importar Usuarios de {mediaServerName}",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Dispositivo Predeterminado",
"components.ManageSlideOver.removearr": "Eliminar de {arr}",
"components.NotificationTypeSelector.issuereopenedDescription": "Enviar notificación cuando se reabran incidencias.",
"components.Layout.UserWarnings.emailRequired": "Se requiere una dirección de email.",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken": "Token de Acceso",
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken": "Debes proporcionar un token de aplicación válido",
"components.Settings.syncJellyfin": "Sincronizar Bibliotecas",
"components.Layout.UserWarnings.emailInvalid": "La dirección de correo es inválida.",
"components.Login.description": "Como es la primera vez que inicias sesión en {applicationName}, es necesario añadir una dirección de email válida.",
"components.Login.save": "Añadir",
"components.NotificationTypeSelector.issueresolvedDescription": "Enviar notificación cuando se resuelvan incidencias.",
"components.PermissionEdit.manageissues": "Administrar incidencias",
"components.PermissionEdit.createissues": "Notificar incidencia",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Guardando…",
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken": "Debes indicar un token de acceso",
"components.Login.signinwithjellyfin": "Utiliza tu cuenta de {mediaServerName}",
"components.ManageSlideOver.removearr4k": "Eliminar de {arr} 4K",
"components.Settings.internalUrl": "URL Interna",
"components.TvDetails.play4k": "Reproducir 4K en {mediaServerName}",
"components.Setup.signin": "Iniciar Sesión",
"components.Setup.signinWithJellyfin": "Utiliza tu cuenta de {mediaServerName}",
"components.UserList.noJellyfinuserstoimport": "No hay usuarios de {mediaServerName} que importar.",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "Usuario de {mediaServerName}",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip": "Crea un token desde tu <PushbulletSettingsLink>Opciones de Cuenta</PushbulletSettingsLink>",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed": "No se pudo guardar la configuración de notificaciones de Pushover.",
"components.NotificationTypeSelector.userissuereopenedDescription": "Recibir notificaciones cuando se vuelvan a abrir incidencias que haya reportado.",
"components.NotificationTypeSelector.userissueresolvedDescription": "Reciba notificaciones cuando se resuelvan las incidencias que haya reportado.",
"components.PermissionEdit.createissuesDescription": "Dar permiso para informar incidencias.",
"components.Settings.SettingsAbout.supportjellyseerr": "Apoya a Jellyseerr",
"components.Settings.Notifications.userEmailRequired": "Requerir email de usuario",
"components.Settings.SonarrModal.animeSeriesType": "Tipo de Serie Anime",
"components.Settings.SonarrModal.seriesType": "Tipo Serie",
"components.Settings.jellyfinSettingsDescription": "Opcionalmente, configure los puntos finales internos y externos para su servidor {mediaServerName}. En la mayoría de los casos, la URL externa es diferente a la URL interna. También se puede configurar una URL de restablecimiento de contraseña personalizada para el inicio de sesión de {mediaServerName}, en caso de que desee redirigir a una página de restablecimiento de contraseña diferente.",
"components.Settings.jellyfinsettingsDescription": "Configure los ajustes para su servidor {mediaServerName}. {mediaServerName} escanea sus bibliotecas de {mediaServerName} para ver qué contenido está disponible.",
"components.Settings.manualscanJellyfin": "Escanear Libreria Manualmente",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> Eliminado correctamente de la lista de seguimiento!",
"components.UserList.newJellyfinsigninenabled": "La configuración <strong>Habilitar nuevo inicio de sesión de {mediaServerName}</strong> está actualmente habilitada. Los usuarios de {mediaServerName} con acceso a la biblioteca no necesitan ser importados para poder iniciar sesión.",
"components.UserProfile.localWatchlist": "Lista de seguimiento de {username}"
}

View File

@@ -59,7 +59,7 @@
"components.Discover.DiscoverTvGenre.genreSeries": "Séries {genre}",
"components.Discover.DiscoverTvKeyword.keywordSeries": "{keywordTitle} Séries",
"components.Discover.DiscoverTvLanguage.languageSeries": "Séries en {language}",
"components.Discover.DiscoverWatchlist.discoverwatchlist": "Votre watchlist Plex",
"components.Discover.DiscoverWatchlist.discoverwatchlist": "Votre watchlist",
"components.Discover.DiscoverWatchlist.watchlist": "Watchlist Plex",
"components.Discover.FilterSlideover.activefilters": "{count, plural, one {# Filtre actif} other {# Filtres actifs}}",
"components.Discover.FilterSlideover.clearfilters": "Effacer les filtres actifs",
@@ -1251,5 +1251,71 @@
"components.Settings.SonarrModal.tagRequests": "Tager les demandes",
"components.Settings.SonarrModal.tagRequestsInfo": "Ajouter automatiquement un tag supplémentaire avec l'ID utilisateur et le nom d'affichage du demandeur",
"i18n.collection": "Collection",
"components.Settings.RadarrModal.tagRequestsInfo": "Ajouter automatiquement un tag supplémentaire avec l'ID utilisateur et le nom d'affichage du demandeur"
"components.Settings.RadarrModal.tagRequestsInfo": "Ajouter automatiquement un tag supplémentaire avec l'ID utilisateur et le nom d'affichage du demandeur",
"components.IssueModal.issueVideo": "Vidéo",
"components.Settings.Notifications.NotificationsPushover.sound": "Son de notification",
"components.Settings.jellyfinSettings": "Paramètres pour {mediaServerName}",
"components.Settings.jellyfinSettingsFailure": "Une erreur est survenue lors de l'enregistrement des paramètres pour {mediaServerName}.",
"components.Settings.jellyfinSettingsSuccess": "Les paramètres pour {mediaServerName} ont été enregistrés avec succès!",
"components.Settings.jellyfinlibraries": "Bibliothèques {mediaServerName}",
"components.Settings.jellyfinlibrariesDescription": "Les bibliothèques de {mediaServerName} sont en cours d'analyze. Cliquez sur le bouton ci-dessous si aucune bibliothèque n'est répertoriée.",
"components.Settings.jellyfinsettings": "Paramètres pour {mediaServerName}",
"components.Settings.manualscanJellyfin": "Analyse manuelle de la bibliothèque",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.Settings.save": "Enregistrer les modifications",
"components.Settings.saving": "Sauvegarde en cours…",
"components.Settings.syncing": "Synchronisation en cours",
"components.Setup.signin": "Se connecter",
"components.Setup.signinWithPlex": "Utilisez votre compte Plex",
"components.StatusBadge.managemedia": "Gérer {mediaType}",
"components.StatusBadge.openinarr": "Ouvrir dans {arr}",
"components.StatusBadge.playonplex": "Lire sur {mediaServerName}",
"components.TitleCard.addToWatchList": "Ajouter à votre watchlist",
"components.TitleCard.watchlistCancel": "Watchlist pour <strong>{title}</strong> annulée.",
"components.TitleCard.watchlistError": "Une erreur est survenue. Veuillez réessayer.",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> a été ajouté à votre watchlist avec succès !",
"components.TvDetails.Season.somethingwentwrong": "Une erreur est survenue lors de la récupération des données de la saison.",
"components.TvDetails.manageseries": "Gérer les séries",
"components.TvDetails.play": "Jouer sur {mediaServerName}",
"components.TvDetails.play4k": "Jouer en 4K sur {mediaServerName}",
"components.TvDetails.rtcriticsscore": "Tomatometer sur Rotten Tomatoes",
"components.TvDetails.seasonnumber": "Saison {seasonNumber}",
"components.TvDetails.seasonstitle": "Saisons",
"components.TvDetails.status4k": "{status} 4K",
"components.TvDetails.tmdbuserscore": "Score utilisateur sur TMDB",
"components.UserList.importfromJellyfin": "Importer les utilisateurs de {mediaServerName}",
"components.UserList.importfromJellyfinerror": "Une erreur est survenue lors de l'importation des utilisateurs de {mediaServerName}.",
"components.UserList.importfrommediaserver": "Importer les utilisateurs de {mediaServerName}",
"components.UserList.noJellyfinuserstoimport": "Il n'y a aucun utilisateur à importer pour {mediaServerName}.",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Sauvegarde en cours…",
"components.UserProfile.plexwatchlist": "Watchlist Plex",
"components.Settings.syncJellyfin": "Synchroniser les bibliothèques",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> a été retiré de votre watchlist avec succès !",
"components.IssueModal.issueSubtitles": "Sous-titre",
"components.Login.emailtooltip": "L'adresse ne nécessite pas d'être associée avec votre instance {mediaServerName}.",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Appareil par défaut",
"components.Settings.Notifications.userEmailRequired": "E-mail utilisateur requis",
"components.Settings.SettingsAbout.supportjellyseerr": "Soutenez Jellyseerr",
"components.Settings.SettingsJobsCache.jellyfin-full-scan": "Scan complet des bibliothèques Jellyfin",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Scan des ajouts récents aux bibliothèques Jellyfin",
"components.Settings.SonarrModal.animeSeriesType": "Type de série anime",
"components.Settings.SonarrModal.seriesType": "Type de série",
"components.Settings.internalUrl": "URL interne",
"components.Settings.jellyfinsettingsDescription": "Configurez les paramètres de votre serveur {mediaServerName}. {mediaServerName} analyse vos bibliothèques {mediaServerName} pour voir quel contenu est disponible.",
"components.Settings.jellyfinSettingsDescription": "Configurez facultativement les URL internes et externes pour votre serveur {mediaServerName}. Dans la plupart des cas, l'URL externe est différente de l'URL interne. Vous pouvez également définir une URL de réinitialisation de mot de passe personnalisée pour la connexion à {mediaServerName}, au cas où vous souhaiteriez rediriger vers une page de réinitialisation de mot de passe différente.",
"components.Settings.manualscanDescriptionJellyfin": "Normalement, cette tâche est executée qu'une fois toutes les 24 heures. Jellyseerr vérifiera plus agressivement les éléments récemment ajoutés à votre serveur {mediaServerName}. Si c'est la première fois que vous configurez Jellyseerr, une analyse complète manuelle de la bibliothèque est recommandée !",
"components.Settings.timeout": "Temps écoulé",
"components.Setup.configuremediaserver": "Configurer le serveur multimédia",
"components.TvDetails.rtaudiencescore": "Score de l'audience sur Rotten Tomatoes",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "Utilisateur pour {mediaServerName}",
"components.Setup.signinWithJellyfin": "Utilisez votre compte {mediaServerName}",
"components.UserList.mediaServerUser": "Utilisateur de {mediaServerName}",
"components.TvDetails.episodeCount": "{episodeCount, plural, one {# Épisode} other {# Épisodes}}",
"components.UserList.newJellyfinsigninenabled": "Le paramètre <strong>Activer la nouvelle connexion à {mediaServerName}</strong> est actuellement activé. Les utilisateurs de {mediaServerName} avec accès à la bibliothèque n'ont pas besoin d'être importés pour se connecter.",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "E-mail",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Enregistrer les modifications",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Appareil par défaut",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} importé(s) avec succès !",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Son de notification",
"components.UserProfile.localWatchlist": "Watchlist de {username}"
}

View File

@@ -135,5 +135,67 @@
"components.Login.loginerror": "משהו השתבש בזמן ההתחברות.",
"components.Login.password": "סיסמה",
"components.Login.signin": "התחברות",
"components.Login.validationpasswordrequired": "חובה לכתוב סיסמה"
"components.Login.validationpasswordrequired": "חובה לכתוב סיסמה",
"components.Discover.CreateSlider.editSlider": "ערוך סליידר",
"components.Discover.CreateSlider.editfail": "נכשלה עריכת סליידר.",
"components.Discover.CreateSlider.needresults": "אתה צריך לפחות תוצאה אחת.",
"components.Discover.CreateSlider.nooptions": "אין תוצאות.",
"components.Discover.CreateSlider.providetmdbgenreid": "ספק מזהה ז'אנר TMDB",
"components.Discover.CreateSlider.providetmdbkeywordid": "ספק מזהה מילת מפתח TMDB",
"components.Discover.CreateSlider.providetmdbsearch": "ספק שאילתת חיפוש",
"components.Discover.CreateSlider.providetmdbstudio": "ספק מזהה סטודיו TMDB",
"components.Discover.CreateSlider.searchGenres": "חפש ז'אנרים…",
"components.Discover.CreateSlider.searchKeywords": "חפש מילות מפתח…",
"components.Discover.CreateSlider.searchStudios": "חפש אולפנים…",
"components.Discover.CreateSlider.slidernameplaceholder": "שם הסליידר",
"components.Discover.CreateSlider.validationDatarequired": "עליך לספק ערך.",
"components.Discover.CreateSlider.validationTitlerequired": "עליך לספק כותר.",
"components.Discover.DiscoverMovieKeyword.keywordMovies": "סרטים {keywordTitle}",
"components.Discover.DiscoverMovies.discovermovies": "סרטים",
"components.Discover.DiscoverMovies.sortPopularityAsc": "פופולריות בסדר עולה",
"components.Discover.DiscoverMovies.sortPopularityDesc": "פופולריות בסדר יורד",
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "תאריך שחרור בסדר עולה",
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "תאריך שחרור בסדר יורד",
"components.Discover.DiscoverMovies.sortTitleAsc": "כותר (א-ת, A-Z) עולה",
"components.Discover.DiscoverMovies.sortTitleDesc": "כותר (ת-א, A-Z) יורד",
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "דירוג TMDB בסדר עולה",
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "דירוג TMDB בסדר יורד",
"components.Discover.DiscoverSliderEdit.deletesuccess": "סליידר נמחק בהצלחה.",
"components.Discover.DiscoverSliderEdit.enable": "שנה נראות",
"components.Discover.DiscoverSliderEdit.remove": "הסר",
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {פילטר אחד פעיל} other {# פילטרים פעילים}}",
"components.Discover.DiscoverTv.discovertv": "סדרה",
"components.Discover.CreateSlider.addfail": "נכשלה יצירת סליידר חדש.",
"components.Discover.DiscoverTv.sortPopularityAsc": "פופולריות בסדר עולה",
"components.Discover.DiscoverTv.sortPopularityDesc": "פופולריות בסדר יורד",
"components.Discover.DiscoverTv.sortTitleAsc": "כותר (א-ת, A-Z) עולה",
"components.Discover.DiscoverTv.sortTitleDesc": "כותר (א-ת, A-Z) יורד",
"components.Discover.DiscoverTv.sortTmdbRatingAsc": "דירוג TMDB בסדר עולה",
"components.Discover.DiscoverTvKeyword.keywordSeries": "סדרה {keywordTitle}",
"components.Discover.FilterSlideover.activefilters": "{count, plural, one {פילטר אחד פעיל} other {# פילטרים פעילים}}",
"components.Discover.FilterSlideover.clearfilters": "נקה פילטרים פעילים",
"components.Discover.FilterSlideover.filters": "פילטרים",
"components.Discover.FilterSlideover.firstAirDate": "תאריך שידור ראשון",
"components.Discover.FilterSlideover.from": "מאת",
"components.Discover.FilterSlideover.keywords": "מילות מפתח",
"components.Discover.FilterSlideover.originalLanguage": "שפה מקורית",
"components.Discover.FilterSlideover.ratingText": "דירוג בין {minValue} ל {maxValue}",
"components.Discover.FilterSlideover.releaseDate": "תאריך שחרור",
"components.Discover.FilterSlideover.runtime": "זמן ריצה",
"components.Discover.FilterSlideover.streamingservices": "שירותי הזרמה",
"components.Discover.FilterSlideover.studio": "אולפן",
"components.Discover.FilterSlideover.tmdbuserscore": "דירוג משתמש TMDB",
"components.Discover.CreateSlider.addSlider": "הוסף סליידר",
"components.Discover.CreateSlider.addcustomslider": "צור סליידר מותאם",
"components.Discover.CreateSlider.addsuccess": "סליידר חדש נוצר בהצלחה ונשמרו הגדרות התאמה.",
"components.Discover.CreateSlider.providetmdbnetwork": "ספק מזהה רשת TMDB",
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "תאריך שידור ראשון בסדר יורד",
"components.Discover.CreateSlider.starttyping": "התחל להזין כדי לחפש.",
"components.Discover.FilterSlideover.runtimeText": "זמן ריצה בין {minValue} ל {maxValue}",
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {פילטר פעיל} other {# פילטרים פעילים}}",
"components.Discover.DiscoverSliderEdit.deletefail": "כשל במחיקת סליידר.",
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "תאריך שידור ראשון בסדר עולה",
"components.Discover.CreateSlider.editsuccess": "סליידר נערך ונשמר בהצלחה.",
"components.Discover.DiscoverTv.sortTmdbRatingDesc": "דירוג TMDB בסדר יורד",
"components.Discover.FilterSlideover.genres": "ז'אנרים"
}

View File

@@ -1152,7 +1152,7 @@
"components.Settings.SettingsMain.applicationurl": "URL applicazione",
"components.Settings.SettingsMain.validationApplicationTitle": "Devi fornire un titolo dell'applicazione",
"components.Settings.SettingsMain.validationApplicationUrl": "Devi fornire un URL valido",
"components.Settings.restartrequiredTooltip": "Overseerr deve essere riavviato per rendere effettive le modifiche",
"components.Settings.restartrequiredTooltip": "Jellyseerr deve essere riavviato per rendere effettive le modifiche",
"components.TitleCard.tvdbid": "TheTVDB ID",
"components.UserProfile.emptywatchlist": "I media aggiunti alla tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> appariranno qui.",
"components.TvDetails.status4k": "4K {status}",

View File

@@ -324,13 +324,13 @@
"components.Settings.SettingsAbout.appDataPath": "데이터 디렉토리",
"components.Settings.SettingsAbout.documentation": "문서",
"components.Settings.SettingsAbout.gettingsupport": "지원 받기",
"components.Settings.SettingsAbout.overseerrinformation": "Overseerr 정보",
"components.Settings.SettingsAbout.overseerrinformation": "Jellyseerr 정보",
"components.Settings.SettingsAbout.preferredmethod": "선호",
"components.Settings.SettingsAbout.runningDevelop": "당신은 <code>개발</code>에 기여하거나 최신 테스트를 지원하는 사람들에게만 권장되는 Overserr 분기를 실행하고 있습니다.",
"components.Settings.SettingsAbout.timezone": "시간대",
"components.Settings.SettingsJobsCache.availability-sync": "사용가능한 미디어 동기화",
"components.Settings.SettingsJobsCache.cache": "캐시",
"components.Settings.SettingsJobsCache.cacheDescription": "Overseerr는 외부 API 엔드포인트에 대한 요청을 캐시하여 성능을 최적화하고 불필요한 API 호출을 방지합니다.",
"components.Settings.SettingsJobsCache.cacheDescription": "Jellyseerr는 외부 API 엔드포인트에 대한 요청을 캐시하여 성능을 최적화하고 불필요한 API 호출을 방지합니다.",
"components.Settings.SettingsJobsCache.cacheflushed": "{cachename} 캐시가 플러시되었습니다.",
"components.Settings.SettingsJobsCache.cachekeys": "전체 키",
"components.Settings.SettingsJobsCache.cacheksize": "키 크기",
@@ -342,11 +342,11 @@
"components.Settings.SettingsJobsCache.editJobSchedulePrompt": "새 주파수",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "매 {jobScheduleSeconds, plural, one {초} other {{jobScheduleSeconds} 초}}",
"components.Settings.SettingsJobsCache.imagecache": "이미지 캐시",
"components.Settings.SettingsJobsCache.imagecacheDescription": "설정에서 활성화하면 Overseerr는 미리 구성된 외부 소스에서 이미지를 프록시하고 캐시합니다. 캐시된 이미지는 구성 폴더에 저장됩니다. <code>{appDataPath}/cache/images</code> 에서 파일을 찾을 수 있습니다.",
"components.Settings.SettingsJobsCache.imagecacheDescription": "설정에서 활성화하면 Jellyseerr는 미리 구성된 외부 소스에서 이미지를 프록시하고 캐시합니다. 캐시된 이미지는 구성 폴더에 저장됩니다. <code>{appDataPath}/cache/images</code> 에서 파일을 찾을 수 있습니다.",
"components.Settings.SettingsJobsCache.jobScheduleEditFailed": "작업을 저장하는 동안 문제가 발생했습니다.",
"components.Settings.SettingsJobsCache.jobScheduleEditSaved": "작업이 성공적으로 수정되었습니다!",
"components.Settings.SettingsJobsCache.jobs": "작업",
"components.Settings.SettingsJobsCache.jobsDescription": "Overseerr는 특정 유지 관리 작업을 정기적으로 예약된 작업으로 수행하지만 아래에서 수동으로 트리거할 수도 있습니다. 작업을 수동으로 실행해도 일정이 변경되지는 않습니다.",
"components.Settings.SettingsJobsCache.jobsDescription": "Jellyseerr는 특정 유지 관리 작업을 정기적으로 예약된 작업으로 수행하지만 아래에서 수동으로 트리거할 수도 있습니다. 작업을 수동으로 실행해도 일정이 변경되지는 않습니다.",
"components.Settings.SettingsJobsCache.jobtype": "유형",
"components.Settings.SettingsJobsCache.plex-full-scan": "Plex 전체 라이브러리 스캔",
"components.Settings.SettingsJobsCache.plex-recently-added-scan": "Plex 최근 추가 스캔",
@@ -420,7 +420,7 @@
"components.Settings.is4k": "4K",
"components.Settings.manualscan": "수동으로 라이브러리 스캔",
"components.Settings.mediaTypeMovie": "영화",
"components.Settings.manualscanDescription": "일반적으로 이는 24시간에 한 번 실행됩니다. Overseerr는 Plex 서버의 최근 추가 항목을 더 적극적으로 확인합니다. 만약 Plex를 처음 구성하는 경우, 한번은 전체 수동 라이브러리 스캔을 권장합니다!",
"components.Settings.manualscanDescription": "일반적으로 이는 24시간에 한 번 실행됩니다. Jellyseerr는 Plex 서버의 최근 추가 항목을 더 적극적으로 확인합니다. 만약 Plex를 처음 구성하는 경우, 한번은 전체 수동 라이브러리 스캔을 권장합니다!",
"components.Settings.mediaTypeSeries": "시리즈",
"components.Settings.menuAbout": "정보",
"components.Settings.menuGeneralSettings": "일반",
@@ -431,10 +431,10 @@
"components.Settings.noDefaultNon4kServer": "비-4K 및 4K 콘텐츠를 전부 처리하는 유일한 {serverType} 서버가 있는 경우(또는 4K 콘텐츠만 다운로드하는 경우), {serverType} 서버는 4K 서버로 지정되어서는 <strong>안됩니다</strong>.",
"components.Settings.noDefaultServer": "{mediaType} 요청을 처리하기 위해서는 적어도 하나 이상의 {serverType} 서버를 기본 설정해야 합니다.",
"components.Settings.notifications": "알림",
"components.Settings.plexlibrariesDescription": "Overseerr에서 타이틀을 스캔하는 라이브러리입니다. Plex 연결 설정을 설정하고 저장한 후, 라이브러리가 표시되지 않는 경우 아래 버튼을 클릭하세요.",
"components.Settings.plexlibrariesDescription": "Jellyseerr에서 타이틀을 스캔하는 라이브러리입니다. Plex 연결 설정을 설정하고 저장한 후, 라이브러리가 표시되지 않는 경우 아래 버튼을 클릭하세요.",
"components.Settings.port": "포트",
"components.Settings.radarrsettings": "Radarr 설정",
"components.Settings.restartrequiredTooltip": "이 변경된 설정이 적용되려면 Overseerr를 재시작해야 합니다",
"components.Settings.restartrequiredTooltip": "이 변경된 설정이 적용되려면 Jellyseerr를 재시작해야 합니다",
"components.Settings.serverRemote": "원격",
"components.Settings.serverSecure": "보안",
"components.Settings.serverpreset": "서버",
@@ -598,7 +598,7 @@
"components.IssueList.showallissues": "모든 이슈 표시",
"components.IssueModal.CreateIssueModal.toastFailedCreate": "이슈를 제출하는 동안에 문제가 발생했습니다.",
"components.Layout.LanguagePicker.displaylanguage": "표시 언어",
"components.Layout.VersionStatus.streamdevelop": "Overseerr 개발",
"components.Layout.VersionStatus.streamdevelop": "Jellyseerr 개발",
"components.ManageSlideOver.tvshow": "시리즈",
"components.ManageSlideOver.plays": "<strong>{playCount, number}</strong> {playCount, plural, one {재생} other {재생}}",
"components.MovieDetails.rtaudiencescore": "Rotten Tomatoes 시청자 점수",
@@ -690,7 +690,7 @@
"components.Layout.Sidebar.issues": "이슈",
"components.Layout.UserDropdown.myprofile": "프로필",
"components.Login.loginerror": "로그인을 시도하는 중에 문제가 발생했습니다.",
"components.Layout.VersionStatus.streamstable": "Overseerr 안정",
"components.Layout.VersionStatus.streamstable": "Jellyseerr 안정",
"components.Login.signingin": "로그인 중…",
"components.ManageSlideOver.manageModalIssues": "진행 중인 이슈",
"components.ManageSlideOver.manageModalMedia": "미디어",
@@ -780,7 +780,7 @@
"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess": "Pushbullet 테스트 알림이 전송되었습니다!",
"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed": "Pushbullet 테스트 알림을 보내지 못했습니다.",
"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending": "Pushbullet 테스트 알림 보내기…",
"components.Settings.Notifications.NotificationsPushover.accessTokenTip": "Overseerr와 함께 사용할 <ApplicationRegistrationLink>애플리케이션 등록</ApplicationRegistrationLink>",
"components.Settings.Notifications.NotificationsPushover.accessTokenTip": "Jellyseerr와 함께 사용할 <ApplicationRegistrationLink>애플리케이션 등록</ApplicationRegistrationLink>",
"components.Settings.Notifications.NotificationsPushover.agentenabled": "에이전트 활성화",
"components.Settings.Notifications.NotificationsPushbullet.validationTypes": "적어도 하나 이상의 알림 유형을 선택해야 합니다",
"components.Settings.Notifications.NotificationsPushover.accessToken": "애플리케이션 API 토큰",
@@ -796,7 +796,7 @@
"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "유효한 JSON 페이로드를 입력해야 합니다",
"components.Settings.Notifications.allowselfsigned": "자체 서명된 인증서 허용",
"components.Settings.Notifications.authUser": "SMTP 사용자 이름",
"components.Settings.Notifications.botApiTip": "Overseerr와 함께 사용할 <CreateBotLink>봇 생성</CreateBotLink>이 필요합니다",
"components.Settings.Notifications.botApiTip": "Jellyseerr와 함께 사용할 <CreateBotLink>봇 생성</CreateBotLink>이 필요합니다",
"components.Settings.Notifications.botUsername": "봇 사용자 이름",
"components.Settings.Notifications.chatIdTip": "봇과 채팅을 시작하고 <GetIdBotLink>@get_id_bot</GetIdBotLink>, <code>/my_id</code> 명령을 실행하세요",
"components.Settings.Notifications.discordsettingsfailed": "Discord 알림 설정을 저장하지 못했습니다.",
@@ -840,7 +840,7 @@
"components.Settings.SettingsMain.originallanguageTip": "원작 언어로 콘텐츠 필터링",
"components.Settings.SettingsMain.partialRequestsEnabled": "부분 시리즈 요청 허용",
"components.Settings.SettingsMain.trustProxy": "프록시 지원 활성화",
"components.Settings.SettingsMain.trustProxyTip": "프록시 뒤에서 클라이언트 IP 주소를 정확하게 등록하도록 Overseerr에 허용",
"components.Settings.SettingsMain.trustProxyTip": "프록시 뒤에서 클라이언트 IP 주소를 정확하게 등록하도록 Jellyseerr에 허용",
"components.Settings.SettingsUsers.localLoginTip": "사용자가 Plex OAuth 대신 이메일 주소와 암호를 사용하여 로그인하도록 허용",
"components.Settings.SettingsUsers.movieRequestLimitLabel": "전역 영화 요청 제한",
"components.Settings.SettingsUsers.toastSettingsSuccess": "사용자 설정이 성공적으로 저장되었습니다!",
@@ -1081,6 +1081,7 @@
"components.Settings.Notifications.encryptionTip": "대부분의 경우 암시적 TLS는 465 포트를 사용하고 STARTTLS는 587 포트를 사용합니다",
"components.Settings.SettingsAbout.Releases.versionChangelog": "{version} 변경 로그",
"components.Settings.SettingsAbout.supportoverseerr": "Overseerr 지원",
"components.Settings.SettingsAbout.supportjellyseerr": "Jellyseerr 지원",
"components.Settings.SettingsAbout.uptodate": "최신",
"components.Settings.SettingsAbout.githubdiscussions": "GitHub 토론",
"components.Settings.SettingsAbout.version": "버전",
@@ -1098,7 +1099,7 @@
"components.Settings.SettingsLogs.extraData": "추가 데이터",
"components.Settings.SettingsLogs.time": "타임스탬프",
"components.Settings.SettingsMain.cacheImages": "이미지 캐싱 활성화",
"components.Settings.SettingsMain.generalsettingsDescription": "Overseerr에 대한 전역 및 기본 설정을 구성합니다.",
"components.Settings.SettingsMain.generalsettingsDescription": "Jellyseerr에 대한 전역 및 기본 설정을 구성합니다.",
"components.Settings.SettingsLogs.viewdetails": "세부 정보 보기",
"components.Settings.SettingsMain.applicationurl": "애플리케이션 URL",
"components.Settings.SettingsMain.apikey": "API 키",
@@ -1138,7 +1139,7 @@
"components.Settings.librariesRemaining": "남은 라이브러리: {count}",
"components.Settings.noDefault4kServer": "4K {serverType} 서버는 사용자가 4K {mediaType} 요청을 제출할 수 있도록 기본 설정되어야 합니다.",
"components.Settings.scan": "라이브러리 동기화",
"components.Settings.plexsettingsDescription": "Plex 서버의 설정을 구성하세요. Overseerr는 Plex 라이브러리를 스캔하여 콘텐츠의 사용 가능성을 판단합니다.",
"components.Settings.plexsettingsDescription": "Plex 서버의 설정을 구성하세요. Jellyseerr는 Plex 라이브러리를 스캔하여 콘텐츠의 사용 가능성을 판단합니다.",
"components.Settings.notificationsettings": "알림 설정",
"components.Settings.plexsettings": "Plex 설정",
"components.Settings.notificationAgentSettingsDescription": "알림 에이전트를 구성하고 활성화합니다.",
@@ -1155,7 +1156,7 @@
"components.Settings.webAppUrlTip": "사용자에게 \"호스팅된\" 웹 앱 대신 서버의 웹 앱으로 이동하도록 선택적으로 설정할 수 있습니다",
"components.Setup.setup": "설정",
"components.Setup.tip": "팁",
"components.Setup.welcome": "Overseerr에 오신 것을 환영합니다",
"components.Setup.welcome": "Jellyseerr에 오신 것을 환영합니다",
"components.StatusBadge.status4k": "4K {status}",
"components.StatusBadge.status": "{status}",
"components.TvDetails.play4konplex": "Plex에서 4K로 재생",
@@ -1226,7 +1227,7 @@
"pages.errormessagewithcode": "{statusCode} - {error}",
"pages.serviceunavailable": "서비스를 사용할 수 없음",
"components.Settings.settingUpPlexDescription": "Plex를 설정하려면, 세부 정보를 수동으로 입력하거나 <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>에서 검색된 서버를 선택할 수 있습니다. 사용 가능한 서버 목록을 불러오려면 드롭다운 오른쪽에 있는 버튼을 누르세요.",
"components.Settings.tautulliSettingsDescription": "선택적으로 Tautulli 서버의 설정을 구성하세요. Overseerr는 Tautulli로부터 Plex 미디어의 시청 기록 데이터를 불러옵니다.",
"components.Settings.tautulliSettingsDescription": "선택적으로 Tautulli 서버의 설정을 구성하세요. Jellyseerr는 Tautulli로부터 Plex 미디어의 시청 기록 데이터를 불러옵니다.",
"components.RequestBlock.requestdate": "요청 일자",
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {# 선택한 필터} other {# 선택한 필터}}",
"components.QuotaSelector.seasons": "{count, plural, one {시즌} other {시즌}}",

View File

@@ -3,12 +3,12 @@
"components.Discover.discovertv": "Populaire series",
"components.Discover.popularmovies": "Populaire films",
"components.Discover.populartv": "Populaire series",
"components.Discover.recentlyAdded": "Recent toegevoegd",
"components.Discover.recentlyAdded": "Onlangs toegevoegd",
"components.Discover.recentrequests": "Recente verzoeken",
"components.Discover.trending": "Trending",
"components.Discover.upcoming": "Verwachte films",
"components.Discover.upcomingmovies": "Verwachte films",
"components.Layout.SearchInput.searchPlaceholder": "Zoek films en series",
"components.Layout.SearchInput.searchPlaceholder": "Films en series zoeken",
"components.Layout.Sidebar.dashboard": "Ontdekken",
"components.Layout.Sidebar.requests": "Verzoeken",
"components.Layout.Sidebar.settings": "Instellingen",
@@ -16,7 +16,7 @@
"components.Layout.UserDropdown.signout": "Uitloggen",
"components.MovieDetails.budget": "Budget",
"components.MovieDetails.cast": "Cast",
"components.MovieDetails.originallanguage": "Originele taal",
"components.MovieDetails.originallanguage": "Oorspronkelijke taal",
"components.MovieDetails.overview": "Overzicht",
"components.MovieDetails.overviewunavailable": "Overzicht niet beschikbaar.",
"components.MovieDetails.recommendations": "Aanbevelingen",
@@ -114,7 +114,7 @@
"components.Settings.hostname": "Hostnaam of IP-adres",
"components.Settings.librariesRemaining": "Resterende bibliotheken: {count}",
"components.Settings.manualscan": "Handmatige bibliotheekscan",
"components.Settings.manualscanDescription": "Normaal wordt dit eens elke 24 uur uitgevoerd. Jellyseerr controleert de recent toegevoegde items van je Plex-server agressiever. Als je Plex voor de eerste keer configureert, is een eenmalige handmatige volledige bibliotheekscan aanbevolen!",
"components.Settings.manualscanDescription": "Normaliter wordt dit eenmaal per 24 uur uitgevoerd. Jellyseerr zal de lijst met onlangs toegevoegde media op je Plex-server vaker controleren. Als dit de eerste keer is dat je Jellyseerr instelt, wordt aanbevolen eenmalig een handmatige, volledige bibliotheekscan uit te voeren!",
"components.Settings.menuAbout": "Over",
"components.Settings.menuGeneralSettings": "Algemeen",
"components.Settings.menuJobs": "Taken en cache",
@@ -127,7 +127,7 @@
"components.Settings.plexlibraries": "Plex-bibliotheken",
"components.Settings.plexlibrariesDescription": "De bibliotheken die Jellyseerr scant voor titels. Stel je Plex-verbinding in en sla ze op. Klik daarna op de onderstaande knop als er geen bibliotheken staan.",
"components.Settings.plexsettings": "Plex-instellingen",
"components.Settings.plexsettingsDescription": "Configureer de instellingen voor je Plex-server. Jellyseerr scant je Plex-bibliotheken om te zien welke content beschikbaar is.",
"components.Settings.plexsettingsDescription": "Configureer de instellingen voor je Plex-server. Jellyseerr scant je Plex-bibliotheken om te zien welke inhoud beschikbaar is.",
"components.Settings.port": "Poort",
"components.Settings.radarrsettings": "Radarr-instellingen",
"components.Settings.sonarrsettings": "Sonarr-instellingen",
@@ -137,12 +137,12 @@
"components.Setup.configureservices": "Diensten configureren",
"components.Setup.continue": "Doorgaan",
"components.Setup.finish": "Installatie voltooien",
"components.Setup.finishing": "Bezig met voltooien…",
"components.Setup.finishing": "Voltooien…",
"components.Setup.loginwithplex": "Inloggen met Plex",
"components.Setup.signinMessage": "Ga aan de slag door in te loggen met je Plex-account",
"components.Setup.signinMessage": "Ga aan de slag door je aan te melden",
"components.Setup.welcome": "Welkom bij Jellyseerr",
"components.TvDetails.cast": "Cast",
"components.TvDetails.originallanguage": "Originele taal",
"components.TvDetails.originallanguage": "Oorspronkelijke taal",
"components.TvDetails.overview": "Overzicht",
"components.TvDetails.overviewunavailable": "Overzicht niet beschikbaar.",
"components.TvDetails.recommendations": "Aanbevelingen",
@@ -164,7 +164,7 @@
"i18n.movies": "Films",
"i18n.partiallyavailable": "Deels beschikbaar",
"i18n.pending": "In behandeling",
"i18n.processing": "Bezig met verwerken",
"i18n.processing": "Verwerken",
"i18n.tvshows": "Series",
"i18n.unavailable": "Niet beschikbaar",
"pages.oops": "Oeps",
@@ -187,14 +187,14 @@
"components.Setup.tip": "Tip",
"components.Settings.SonarrModal.testFirstRootFolders": "Test verbinding om hoofdmappen te laden",
"components.Settings.SonarrModal.testFirstQualityProfiles": "Test verbinding om kwaliteitsprofielen te laden",
"components.Settings.SonarrModal.loadingrootfolders": "Bezig met laden van hoofdmappen…",
"components.Settings.SonarrModal.loadingprofiles": "Bezig met laden van kwaliteitsprofielen…",
"components.Settings.SonarrModal.loadingrootfolders": "Hoofdmappen laden…",
"components.Settings.SonarrModal.loadingprofiles": "Kwaliteitsprofielen laden…",
"components.Settings.SettingsAbout.gettingsupport": "Ondersteuning krijgen",
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "Je moet een minimale beschikbaarheid selecteren",
"components.Settings.RadarrModal.testFirstRootFolders": "Test verbinding om hoofdmappen te laden",
"components.Settings.RadarrModal.testFirstQualityProfiles": "Test verbinding om kwaliteitsprofielen te laden",
"components.Settings.RadarrModal.loadingrootfolders": "Bezig met laden van hoofdmappen…",
"components.Settings.RadarrModal.loadingprofiles": "Bezig met laden van kwaliteitsprofielen…",
"components.Settings.RadarrModal.loadingrootfolders": "Hoofdmappen laden…",
"components.Settings.RadarrModal.loadingprofiles": "Kwaliteitsprofielen laden…",
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Versiegegevens zijn momenteel niet beschikbaar.",
"components.Settings.SettingsAbout.Releases.latestversion": "Nieuwste",
"components.Settings.SettingsAbout.Releases.currentversion": "Huidig",
@@ -208,7 +208,7 @@
"i18n.retry": "Opnieuw proberen",
"i18n.requested": "Aangevraagd",
"i18n.failed": "Mislukt",
"i18n.deleting": "Bezig met verwijderen…",
"i18n.deleting": "Verwijderen…",
"i18n.close": "Sluiten",
"components.UserList.userdeleteerror": "Er ging iets mis bij het verwijderen van de gebruiker.",
"components.UserList.userdeleted": "Gebruiker succesvol verwijderd!",
@@ -303,10 +303,10 @@
"components.UserList.create": "Aanmaken",
"components.UserList.createlocaluser": "Lokale gebruiker aanmaken",
"components.UserList.usercreatedfailed": "Er ging iets mis bij het aanmaken van de gebruiker.",
"components.UserList.creating": "Bezig met aanmaken…",
"components.UserList.creating": "Aanmaken…",
"components.UserList.validationpasswordminchars": "Wachtwoord is te kort; moet minimaal 8 tekens bevatten",
"components.UserList.usercreatedsuccess": "Gebruiker succesvol aangemaakt!",
"components.UserList.passwordinfodescription": "Configureer een applicatie-URL en schakel e-mailmeldingen in om automatische wachtwoordgeneratie mogelijk te maken.",
"components.UserList.passwordinfodescription": "Stel een applicatie-URL in en schakel e-mailmeldingen in om automatische wachtwoordgeneratie mogelijk te maken.",
"components.UserList.password": "Wachtwoord",
"components.UserList.localuser": "Lokale gebruiker",
"components.UserList.email": "E-mailadres",
@@ -340,23 +340,23 @@
"components.RequestModal.SearchByNameModal.notvdbiddescription": "We kunnen deze serie niet automatisch matchen. Selecteer hieronder de juiste match.",
"components.Login.signinwithplex": "Plex-account gebruiken",
"components.Login.signinheader": "Log in om verder te gaan",
"components.Login.signingin": "Bezig met inloggen…",
"components.Login.signingin": "Aanmelden…",
"components.Login.signin": "Inloggen",
"components.Settings.notificationAgentSettingsDescription": "Meldingsagenten configureren en inschakelen.",
"components.PlexLoginButton.signinwithplex": "Inloggen",
"components.PlexLoginButton.signingin": "Bezig met inloggen…",
"components.PlexLoginButton.signingin": "Aanmelden…",
"components.PermissionEdit.advancedrequest": "Geavanceerde aanvragen",
"components.PermissionEdit.admin": "Beheerder",
"components.UserList.userssaved": "Gebruikersrechten succesvol opgeslagen!",
"components.Settings.toastPlexRefreshSuccess": "Serverlijst van Plex succesvol opgehaald!",
"components.Settings.toastPlexRefresh": "Bezig met serverlijst ophalen van Plex…",
"components.Settings.toastPlexConnecting": "Bezig met verbinden met Plex-server…",
"components.Settings.toastPlexConnecting": "Verbinden met Plex…",
"components.UserList.bulkedit": "Meerdere bewerken",
"components.Settings.toastPlexRefreshFailure": "Kan serverlijst van Plex niet ophalen.",
"components.Settings.toastPlexConnectingSuccess": "Succesvol verbonden met Plex-server!",
"components.Settings.toastPlexConnectingFailure": "Kan geen verbinding maken met Plex.",
"components.Settings.settingUpPlexDescription": "Om Plex in te stellen, kan je de gegevens handmatig invoeren of een server selecteren die is opgehaald van <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Druk op de knop rechts van de vervolgkeuzelijst om de lijst van beschikbare servers op te halen.",
"components.Settings.serverpresetRefreshing": "Bezig met servers ophalen…",
"components.Settings.serverpresetRefreshing": "Servers ophalen…",
"components.Settings.serverpresetManualMessage": "Handmatige configuratie",
"components.Settings.serverpresetLoad": "Klik op de knop om de beschikbare servers te laden",
"components.Settings.serverpreset": "Server",
@@ -431,7 +431,7 @@
"components.RequestModal.AdvancedRequester.requestas": "Aanvragen als",
"components.Discover.discover": "Ontdekken",
"components.Settings.validationApplicationTitle": "Je moet een toepassingstitel opgeven",
"components.AppDataWarning.dockerVolumeMissingDescription": "De volumekoppeling <code>{appDataPath}</code> was niet correct geconfigureerd. Alle gegevens zullen worden gewist wanneer de container wordt gestopt of opnieuw wordt gestart.",
"components.AppDataWarning.dockerVolumeMissingDescription": "De volumekoppeling <code>{appDataPath}</code> is niet correct geconfigureerd. Alle gegevens zullen worden gewist wanneer de container wordt gestopt of opnieuw wordt gestart.",
"components.Settings.validationApplicationUrlTrailingSlash": "URL mag niet eindigen op een schuine streep",
"components.Settings.validationApplicationUrl": "Je moet een geldige URL opgeven",
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL mag niet eindigen op een schuine streep",
@@ -520,7 +520,7 @@
"components.Layout.UserDropdown.myprofile": "Profiel",
"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Je moet een geldige gebruikers-ID opgeven",
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "Het <FindDiscordIdLink>meercijferige ID-nummer</FindDiscordIdLink> van je gebruikersaccount",
"components.CollectionDetails.requestcollection4k": "Collectie in 4K aanvragen",
"components.CollectionDetails.requestcollection4k": "Collectie aanvragen in 4K",
"components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Inhoud filteren op regionale beschikbaarheid",
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Regio van Ontdekken",
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Inhoud filteren op oorspronkelijke taal",
@@ -546,7 +546,7 @@
"components.Settings.SettingsJobsCache.download-sync-reset": "Reset download sync",
"components.Settings.SettingsJobsCache.download-sync": "Synchronisatie downloads",
"components.TvDetails.seasons": "{seasonCount, plural, one {# seizoen} other {# seizoenen}}",
"i18n.loading": "Bezig met laden…",
"i18n.loading": "Laden…",
"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Je moet een geldige chat-ID opgeven",
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Een chat starten</TelegramBotLink>, <GetIdBotLink>@get_id_bot</GetIdBotLink> toevoegen en de opdracht <code>/my_id</code> geven",
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat-ID",
@@ -558,14 +558,14 @@
"components.Discover.DiscoverNetwork.networkSeries": "Series van {network}",
"components.Discover.DiscoverMovieGenre.genreMovies": "{genre} films",
"components.Setup.scanbackground": "Het scannen wordt op de achtergrond uitgevoerd. Je kunt in de tussentijd doorgaan met het installatieproces.",
"components.Settings.scanning": "Bezig met synchroniseren…",
"components.Settings.scanning": "Synchroniseren…",
"components.Settings.scan": "Bibliotheken synchroniseren",
"components.Settings.SettingsJobsCache.sonarr-scan": "Sonarr-scan",
"components.Settings.SettingsJobsCache.radarr-scan": "Radarr-scan",
"components.Settings.SettingsJobsCache.plex-recently-added-scan": "Plex recent toegevoegde scan",
"components.Settings.SettingsJobsCache.plex-full-scan": "Plex volledige bibliotheekscan",
"components.Settings.SettingsJobsCache.jellyfin-full-scan": "volledige bibliotheekscan Jellyfin",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Jellyfin recent toegevoegde scan",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Scan van 'onlangs toegevoegd' in Jellyfin",
"components.Settings.Notifications.validationUrl": "Je moet een geldige URL opgeven",
"components.Settings.Notifications.botAvatarUrl": "URL bot-avatar",
"components.RequestList.RequestItem.requested": "Aangevraagd",
@@ -670,27 +670,27 @@
"components.QuotaSelector.unlimited": "Onbeperkt",
"i18n.view": "Bekijken",
"i18n.tvshow": "Serie",
"i18n.testing": "Bezig met testen…",
"i18n.testing": "Testen…",
"i18n.test": "Test",
"i18n.status": "Status",
"i18n.showingresults": "<strong>{from}</strong> tot <strong>{to}</strong> van de <strong>{total}</strong> resultaten worden weergegeven",
"i18n.saving": "Bezig met opslaan…",
"i18n.saving": "Opslaan…",
"i18n.save": "Wijzigingen opslaan",
"i18n.resultsperpage": "{pageSize} resultaten per pagina weergeven",
"i18n.requesting": "Bezig met aanvragen…",
"i18n.requesting": "Aanvragen…",
"i18n.request4k": "Aanvragen in 4K",
"i18n.previous": "Vorige",
"i18n.notrequested": "Niet aangevraagd",
"i18n.noresults": "Geen resultaten.",
"i18n.next": "Volgende",
"i18n.movie": "Film",
"i18n.canceling": "Bezig met annuleren…",
"i18n.canceling": "Annuleren…",
"i18n.back": "Terug",
"i18n.areyousure": "Weet je het zeker?",
"i18n.all": "Alle",
"components.RequestModal.QuotaDisplay.requiredquotaUser": "Deze gebruiker heeft nog minstens <strong>{seasons}</strong> {seasons, plural, one {seizoensverzoek} other {seizoensverzoeken}} nodig om deze serie aan te vragen.",
"components.TvDetails.originaltitle": "Originele titel",
"components.MovieDetails.originaltitle": "Originele titel",
"components.TvDetails.originaltitle": "Oorspronkelijke titel",
"components.MovieDetails.originaltitle": "Oorspronkelijke titel",
"components.LanguageSelector.originalLanguageDefault": "Alle talen",
"components.LanguageSelector.languageServerDefault": "Standaard ({language})",
"components.Settings.SonarrModal.testFirstTags": "Test de verbinding om labels te laden",
@@ -733,9 +733,9 @@
"components.RequestModal.pendingapproval": "Je verzoek is in afwachting van goedkeuring.",
"components.RequestList.RequestItem.cancelRequest": "Verzoek annuleren",
"components.NotificationTypeSelector.notificationTypes": "Meldingtypes",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Er is voor jouw account momenteel geen wachtwoord ingesteld. Configureer hieronder een wachtwoord om in te kunnen loggen als een \"lokale gebruiker\" met uw e-mailadres.",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Er is voor jouw account momenteel geen wachtwoord ingesteld. Configureer hieronder een wachtwoord om in te kunnen loggen als een \"lokale gebruiker\" met je e-mailadres.",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Deze gebruikersaccount heeft momenteel geen wachtwoord ingesteld. Configureer hieronder een wachtwoord zodat deze account in staat is om zich aan te melden als een \"lokale gebruiker\".",
"components.Settings.serviceSettingsDescription": "Configureer je {serverType} server(s) hieronder. Je kunt meerdere {serverType} servers verbinden, maar slechts twee ervan kunnen als standaard worden gemarkeerd (één niet-4K en één 4K). Beheerders kunnen vóór de goedkeuring de server die gebruikt wordt om nieuwe aanvragen te verwerken aanpassen.",
"components.Settings.serviceSettingsDescription": "Stel je {serverType}-server(s) hieronder in. Je kunt meerdere {serverType}-servers verbinden, maar slechts twee ervan kunnen als standaard worden gemarkeerd (één niet-4K en één 4K). Beheerders kunnen vóór goedkeuring de server aanpassen die voor nieuwe aanvragen gebruikt wordt.",
"components.Settings.noDefaultServer": "Ten minste één {serverType} server moet als standaard worden gemarkeerd om {mediaType}verzoeken te kunnen verwerken.",
"components.Settings.noDefaultNon4kServer": "Als je slechts één enkele {serverType} server hebt voor zowel niet-4K als 4K-inhoud (of als je alleen 4K-inhoud downloadt), dan moet je {serverType} server <strong>NIET</strong> aangeduid worden als een 4K-server.",
"components.Settings.mediaTypeSeries": "serie",
@@ -747,7 +747,7 @@
"components.Layout.VersionStatus.outofdate": "Verouderd",
"components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} achter",
"components.UserList.autogeneratepasswordTip": "Een door de server gegenereerd wachtwoord naar de gebruiker e-mailen",
"i18n.retrying": "Bezig met opnieuw proberen…",
"i18n.retrying": "Opnieuw proberen…",
"components.Settings.serverSecure": "veilig",
"components.UserList.usercreatedfailedexisting": "Het opgegeven e-mailadres wordt al gebruikt door een andere gebruiker.",
"components.RequestModal.edit": "Verzoek bewerken",
@@ -847,7 +847,7 @@
"components.NotificationTypeSelector.usermediadeclinedDescription": "Een melding ontvangen wanneer je mediaverzoeken worden geweigerd.",
"components.NotificationTypeSelector.usermediaavailableDescription": "Een melding ontvangen wanneer je mediaverzoeken beschikbaar zijn.",
"components.NotificationTypeSelector.usermediaAutoApprovedDescription": "Een melding ontvangen wanneer andere gebruikers nieuwe mediaverzoeken indienen die automatisch worden goedgekeurd.",
"components.Settings.SettingsAbout.betawarning": "Dit is BETA software. Functies kunnen kapot en/of instabiel zijn. Meld eventuele problemen op GitHub!",
"components.Settings.SettingsAbout.betawarning": "Dit is BETA-software. Functies kunnen kapot en/of instabiel zijn. Meld eventuele problemen op GitHub!",
"components.Layout.LanguagePicker.displaylanguage": "Weergavetaal",
"components.MovieDetails.showmore": "Meer tonen",
"components.MovieDetails.showless": "Minder tonen",
@@ -971,7 +971,7 @@
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey": "Je moet een geldige gebruikers- of groepssleutel opgeven",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved": "Instellingen voor Pushbullet-meldingen succesvol opgeslagen!",
"components.IssueDetails.playonplex": "Afspelen op {mediaServerName}",
"components.IssueDetails.play4konplex": "Afspelen in 4K op {mediaServerName}",
"components.IssueDetails.play4konplex": "Afspelen op {mediaServerName} in 4K",
"components.IssueDetails.openin4karr": "Openen in 4K {arr}",
"components.IssueList.IssueItem.episodes": "{episodeCount, plural, one {aflevering} other {afleveringen}}",
"components.IssueList.IssueItem.seasons": "{seasonCount, plural, one {seizoen} other {seizoenen}}",
@@ -982,7 +982,7 @@
"components.NotificationTypeSelector.adminissuereopenedDescription": "Ontvang een melding wanneer problemen door andere gebruikers opnieuw worden ingediend.",
"components.NotificationTypeSelector.issuereopenedDescription": "Stuur meldingen wanneer problemen opnieuw worden ingediend.",
"components.NotificationTypeSelector.userissuereopenedDescription": "Ontvang een bericht wanneer problemen die jij hebt gemeld, opnieuw worden ingediend.",
"components.RequestModal.requestseasons4k": "{seasonCount} {seasonCount, plural, one {seizoen} other {seizoenen}} in 4K aanvragen",
"components.RequestModal.requestseasons4k": "{seasonCount} {seasonCount, plural, one {seizoen} other {seizoenen}} aanvragen in 4K",
"components.RequestModal.requestmovies": "{count} {count, plural, one {film} other {films}} aanvragen",
"components.RequestModal.selectmovies": "Film(s) selecteren",
"components.MovieDetails.productioncountries": "Productie{countryCount, plural, one {land} other {landen}}",
@@ -998,7 +998,7 @@
"components.Settings.Notifications.NotificationsGotify.agentenabled": "Agent inschakelen",
"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved": "Instellingen voor meldingen Gotify succesvol opgeslagen!",
"components.Settings.Notifications.NotificationsGotify.token": "Toepassingstoken",
"i18n.importing": "Bezig met importeren…",
"i18n.importing": "Importeren…",
"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed": "Instellingen voor meldingen Gotify niet opgeslagen.",
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed": "Testmelding Gotify niet verzonden.",
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess": "Testmelding Gotify verzonden!",
@@ -1012,7 +1012,7 @@
"components.UserList.newplexsigninenabled": "De instelling <strong>Nieuwe Plex-aanmelding inschakelen</strong> is momenteel ingeschakeld. Plex-gebruikers met bibliotheektoegang hoeven niet te worden geïmporteerd om in te loggen.",
"components.ManageSlideOver.manageModalAdvanced": "Geavanceerd",
"components.ManageSlideOver.alltime": "Altijd",
"components.ManageSlideOver.markallseasons4kavailable": "Alle seizoenen als beschikbaar in 4K markeren",
"components.ManageSlideOver.markallseasons4kavailable": "Alle seizoenen markeren als beschikbaar in 4K",
"components.ManageSlideOver.opentautulli": "In Tautulli openen",
"components.ManageSlideOver.pastdays": "Afgelopen {days, number} dagen",
"components.ManageSlideOver.playedby": "Afgespeeld door",
@@ -1046,8 +1046,8 @@
"components.UserProfile.emptywatchlist": "Media die zijn toegevoegd aan je <PlexWatchlistSupportLink>Plex Kijklijst</PlexWatchlistSupportLink> verschijnen hier.",
"components.MovieDetails.digitalrelease": "Digitale release",
"i18n.restartRequired": "Opnieuw opstarten vereist",
"components.PermissionEdit.viewrecentDescription": "Toestemming geven om de lijst met recent toegevoegde media te bekijken.",
"components.PermissionEdit.viewrecent": "Recent toegevoegd bekijken",
"components.PermissionEdit.viewrecentDescription": "Toestemming geven om de lijst met onlangs toegevoegde media weer te geven.",
"components.PermissionEdit.viewrecent": "Onlangs toegevoegd weergeven",
"components.Settings.deleteServer": "{serverType}-server verwijderen",
"components.StatusChecker.appUpdated": "{applicationTitle} bijgewerkt",
"components.RequestList.RequestItem.tmdbid": "TMDB ID",
@@ -1072,8 +1072,8 @@
"components.TvDetails.seasonnumber": "Seizoen {seasonNumber}",
"components.TvDetails.Season.somethingwentwrong": "Er ging iets mis bij het ophalen van de seizoensgegevens.",
"components.TvDetails.seasonstitle": "Seizoenen",
"components.Discover.DiscoverWatchlist.discoverwatchlist": "Je Plex-kijklijst",
"components.Discover.plexwatchlist": "Je Plex Kijklijst",
"components.Discover.DiscoverWatchlist.discoverwatchlist": "Jouw kijklijst",
"components.Discover.plexwatchlist": "Jouw kijklijst",
"components.MovieDetails.physicalrelease": "Fysieke release",
"components.PermissionEdit.autorequest": "Automatisch aanvragen",
"components.Settings.SettingsJobsCache.plex-watchlist-sync": "Plex Kijklijst synchroniseren",
@@ -1099,7 +1099,7 @@
"components.TvDetails.manageseries": "Serie beheren",
"components.MovieDetails.managemovie": "Film beheren",
"components.MovieDetails.reportissue": "Probleem melden",
"components.PermissionEdit.autorequestMoviesDescription": "Toestemming geven om niet-4K films in je Plex Kijklijst automatisch aan te vragen.",
"components.PermissionEdit.autorequestMoviesDescription": "Toestemming geven om niet-4K films in je Plex-kijklijst automatisch aan te vragen.",
"components.PermissionEdit.autorequestSeries": "Series automatisch aanvragen",
"components.PermissionEdit.autorequestMovies": "Films automatisch aanvragen",
"components.Settings.experimentalTooltip": "Deze instelling inschakelen, kan leiden tot onverwacht gedrag van de toepassing",
@@ -1152,8 +1152,8 @@
"components.Discover.DiscoverSliderEdit.remove": "Verwijderen",
"components.Discover.resetfailed": "Er is iets fout gegaan bij het resetten van de instellingen van Ontdekken.",
"components.Discover.PlexWatchlistSlider.emptywatchlist": "Media die zijn toegevoegd aan je <PlexWatchlistSupportLink>Plex Kijklijst</PlexWatchlistSupportLink> verschijnen hier.",
"components.Discover.PlexWatchlistSlider.plexwatchlist": "Je Plex Kijklijst",
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Recent toegevoegd",
"components.Discover.PlexWatchlistSlider.plexwatchlist": "Jouw kijklijst",
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Onlangs toegevoegd",
"components.Discover.networks": "Netwerken",
"components.Discover.CreateSlider.searchStudios": "Studio's zoeken…",
"components.Discover.CreateSlider.starttyping": "Begin met typen om te zoeken.",
@@ -1184,8 +1184,8 @@
"components.Discover.DiscoverMovies.sortPopularityAsc": "Populariteit oplopend",
"components.Discover.DiscoverMovies.sortPopularityDesc": "Populariteit aflopend",
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "Releasedatum oplopend",
"components.Discover.DiscoverMovies.sortTitleAsc": "Titel (A-Z) oplopend",
"components.Discover.DiscoverMovies.sortTitleDesc": "Titel (Z-A) aflopend",
"components.Discover.DiscoverMovies.sortTitleAsc": "Titel oplopend (A-Z)",
"components.Discover.DiscoverMovies.sortTitleDesc": "Titel aflopend (Z-A)",
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "TMDB-beoordeling oplopend",
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "TMDB-beoordeling aflopend",
"components.Discover.DiscoverSliderEdit.deletefail": "Slider verwijderen mislukt.",
@@ -1202,7 +1202,7 @@
"components.Discover.FilterSlideover.from": "Van",
"components.Discover.FilterSlideover.genres": "Genres",
"components.Discover.FilterSlideover.keywords": "Trefwoorden",
"components.Discover.FilterSlideover.originalLanguage": "Originele taal",
"components.Discover.FilterSlideover.originalLanguage": "Oorspronkelijke taal",
"components.Discover.FilterSlideover.ratingText": "Beoordelingen tussen {minValue} en {maxValue}",
"components.Discover.FilterSlideover.releaseDate": "Releasedatum",
"components.Discover.FilterSlideover.runtime": "Duur",
@@ -1261,5 +1261,88 @@
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "Elke {jobScheduleSeconds, plural, one {seconde} other {{jobScheduleSeconds} seconden}}",
"components.Settings.SettingsJobsCache.availability-sync": "Synchronisatie van mediabeschikbaarheid",
"components.Discover.tmdbmoviestreamingservices": "Streamingdiensten voor films TMDB",
"components.Discover.tmdbtvstreamingservices": "Streamingdiensten voor series TMDB"
"components.Discover.tmdbtvstreamingservices": "Streamingdiensten voor series TMDB",
"components.Login.validationhostrequired": "{mediaServerName}-URL vereist",
"components.Layout.UserWarnings.emailInvalid": "E-mailadres is ongeldig.",
"components.Login.description": "Aangezien dit de eerste keer is dat je je aanmeldt bij {applicationName}, dien je een geldig e-mailadres op te geven.",
"components.Login.saving": "Toevoegen…",
"components.ManageSlideOver.removearr": "Verwijderen van {arr}",
"components.Settings.RadarrModal.tagRequests": "Aanvragen taggen",
"components.MovieDetails.openradarr4k": "Film openen in 4K-Radarr",
"components.Settings.RadarrModal.tagRequestsInfo": "Automatisch een extra label toevoegen met de gebruikers-id en weergavenaam van de aanvrager",
"components.Settings.SonarrModal.animeSeriesType": "Serietype anime",
"components.Settings.SonarrModal.tagRequestsInfo": "Automatisch een extra label toevoegen met de gebruikers-id en weergavenaam van de aanvrager",
"components.Settings.internalUrl": "Interne URL",
"components.Settings.jellyfinsettings": "{mediaServerName}-instellingen",
"components.Settings.jellyfinlibrariesDescription": "De {mediaServerName}-bibliotheken die op titels worden gescand. Klik op onderstaande knop als er geen bibliotheken in de lijst staan.",
"components.Settings.manualscanDescriptionJellyfin": "Normaliter wordt dit eenmaal per 24 uur uitgevoerd. Jellyseerr zal de lijst met onlangs toegevoegde media op je {mediaServerName}-server vaker controleren. Als dit de eerste keer is dat je Jellyseerr instelt, wordt aanbevolen eenmalig een handmatige, volledige bibliotheekscan uit te voeren!",
"components.Settings.save": "Wijzigingen opslaan",
"components.Settings.syncJellyfin": "Bibliotheken synchoniseren",
"components.TvDetails.play": "Afspelen op {mediaServerName}",
"components.Discover.FilterSlideover.tmdbuservotecount": "Aantal gebruikersstemmen TMDB",
"components.Login.save": "Toevoegen",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Hiermee wordt deze {mediaType} onomkeerbaar verwijderd van {arr}, inclusief alle bestanden.",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Apparaatstandaard",
"components.Settings.Notifications.userEmailRequired": "Gebruikerse-mail vereisen",
"components.Settings.SettingsAbout.supportjellyseerr": "Jellyseerr ondersteunen",
"components.Settings.SonarrModal.seriesType": "Serietype",
"components.Settings.jellyfinSettings": "{mediaServerName}-instellingen",
"components.Setup.configuremediaserver": "Mediaserver instellen",
"components.TvDetails.play4k": "Afspelen op {mediaServerName} in 4K",
"components.UserList.mediaServerUser": "{mediaServerName}-gebruiker",
"components.UserList.noJellyfinuserstoimport": "Er zijn geen {mediaServerName}-gebruikers om te importeren.",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "E-mail",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Apparaatstandaard",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Meldingsgeluid",
"components.Login.signinwithjellyfin": "{mediaServerName}-account gebruiken",
"components.Discover.FilterSlideover.voteCount": "Aantal stemmen tussen {minValue} en {maxValue}",
"components.Layout.UserWarnings.emailRequired": "Een e-mailadres is vereist.",
"components.Layout.UserWarnings.passwordRequired": "Een wachtwoord is vereist.",
"components.Login.credentialerror": "Gebruikersnaam of wachtwoord is onjuist.",
"components.Login.emailtooltip": "Het adres hoeft niet gelieerd te zijn aan je {mediaServerName}-instantie.",
"components.Login.host": "{mediaServerName}-URL",
"components.Login.initialsignin": "Verbinden",
"components.Login.initialsigningin": "Verbinden…",
"components.Login.title": "E-mail toevoegen",
"components.Login.username": "Gebruikersnaam",
"components.Login.validationEmailRequired": "Je moet een e-mailadres opgeven",
"components.Login.validationEmailFormat": "Ongeldig e-mailadres",
"components.Login.validationemailformat": "Geldig e-mailadres vereist",
"components.Login.validationhostformat": "Geldige URL vereist",
"components.Login.validationusernamerequired": "Gebruikersnaam vereist",
"components.ManageSlideOver.removearr4k": "Verwijderen van 4K-{arr}",
"components.MovieDetails.downloadstatus": "Downloadstatus",
"components.MovieDetails.imdbuserscore": "Gebruikersbeoordeling IMDB",
"components.MovieDetails.openradarr": "Film openen in Radarr",
"components.MovieDetails.play": "Afspelen op {mediaServerName}",
"components.MovieDetails.play4k": "Afspelen op {mediaServerName} in 4K",
"components.Settings.Notifications.NotificationsPushover.sound": "Meldingsgeluid",
"components.Settings.SonarrModal.tagRequests": "Aanvragen taggen",
"components.Settings.jellyfinSettingsFailure": "Er is iets misgegaan bij het opslaan van de {mediaServerName}-instellingen.",
"components.Settings.jellyfinSettingsSuccess": "{mediaServerName}-instellingen opgeslagen!",
"components.Settings.jellyfinlibraries": "{mediaServerName}-bibliotheken",
"components.Settings.manualscanJellyfin": "Handmatige bibliotheekscan",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.Settings.saving": "Opslaan…",
"components.Settings.syncing": "Synchroniseren",
"components.Settings.timeout": "Time-out",
"components.Setup.signin": "Aanmelden",
"components.Setup.signinWithJellyfin": "{mediaServerName}-account gebruiken",
"components.TitleCard.addToWatchList": "Toevoegen aan kijklijst",
"components.TitleCard.watchlistError": "Er is iets misgegaan. Probeer het opnieuw.",
"components.UserList.importfromJellyfin": "{mediaServerName}-gebruikers importeren",
"components.UserList.importfromJellyfinerror": "Er is iets misgegaan bij het importeren van {mediaServerName}-gebruikers.",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "{mediaServerName}-gebruiker",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Wijzigingen opslaan",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Opslaan…",
"i18n.collection": "Collectie",
"components.UserProfile.localWatchlist": "Kijklijst van {username}",
"components.Setup.signinWithPlex": "Plex-account gebruiken",
"components.Settings.jellyfinSettingsDescription": "Optioneel, configureer de interne en externe eindpunten voor uw {mediaServerName} server. In de meeste gevallen verschilt de externe URL met de interne URL. Een aangepaste wachtwoord reset URL kan ook gebruikt worden voor de {mediaServerName} login, voor het geval dat u doorverwezen wilt worden naar een andere wachtwoord reset pagina.",
"components.Settings.jellyfinsettingsDescription": "Configureer de instellingen voor uw {mediaServerName} server. {mediaServerName} scanned uw {mediaServerName} bibliotheken om te zien welke content beschikbaar is.",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> Is succesvol verwijderd van de kijklijst!",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> succesvol toegevoegd aan de kijklijst!",
"components.TitleCard.watchlistCancel": "kijklijst voor <strong>{title}</strong> is geannuleerd.",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} succesvol geimporteerd!",
"components.UserList.newJellyfinsigninenabled": "De <strong>Gebruik Nieuwe {mediaServerName} Login</strong> instelling staat momenteel aan. {mediaServerName} gebruikers met toegang tot de bibliotheek, hoeven niet geïmporteerd te worden om in te kunnen loggen."
}

View File

@@ -1060,5 +1060,75 @@
"components.Layout.UserDropdown.requests": "Prośby",
"components.MovieDetails.rtaudiencescore": "Ocena Rotten Tomatoes",
"components.MovieDetails.rtcriticsscore": "Tomatometer Rotten Tomatoes",
"components.MovieDetails.tmdbuserscore": "Ocena użytkowników TMDB"
"components.MovieDetails.tmdbuserscore": "Ocena użytkowników TMDB",
"components.Discover.CreateSlider.addSlider": "Dodaj suwak",
"components.Discover.CreateSlider.addcustomslider": "Utwórz niestandardowy suwak",
"components.Discover.CreateSlider.addfail": "Nie udało się utworzyć nowego suwaka.",
"components.Discover.CreateSlider.addsuccess": "Stworzony nowy suwak i zapisano dostosowywania odkrywania.",
"components.Discover.CreateSlider.editSlider": "Edytuj suwak",
"components.Discover.CreateSlider.editfail": "Nie udało się edytować suwaka.",
"components.Discover.CreateSlider.needresults": "Musisz mieć przynajmniej 1 wynik.",
"components.Discover.CreateSlider.nooptions": "Brak wyników.",
"components.Discover.CreateSlider.providetmdbgenreid": "Podaj ID gatunku TMDB",
"components.Discover.CreateSlider.providetmdbnetwork": "Podaj ID stacji TMDB",
"components.Discover.CreateSlider.providetmdbsearch": "Podaj zapytanie wyszukiwania",
"components.Discover.CreateSlider.providetmdbstudio": "Podaj ID studia TMDB",
"components.Discover.CreateSlider.searchGenres": "Szukaj gatunków…",
"components.Discover.CreateSlider.searchStudios": "Wyszukaj studia…",
"components.Discover.CreateSlider.slidernameplaceholder": "Nazwa suwaka",
"components.Discover.CreateSlider.starttyping": "Zacznij pisać aby wyszukać.",
"components.Discover.CreateSlider.validationDatarequired": "Należy wprowadzić wartość danych.",
"components.Discover.CreateSlider.validationTitlerequired": "Należy podać tytuł.",
"components.Discover.DiscoverMovieKeyword.keywordMovies": "Filmy: {keywordTitle}",
"components.Discover.DiscoverMovies.discovermovies": "Filmy",
"components.Discover.DiscoverMovies.sortPopularityAsc": "Popularność rosnąco",
"components.Discover.DiscoverMovies.sortPopularityDesc": "Popularność malejąco",
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "Data wydania malejąco",
"components.Discover.DiscoverMovies.sortTitleAsc": "Tytuł (A-Z) rosnąco",
"components.Discover.DiscoverMovies.sortTitleDesc": "Tytuł (Z-A) malejąco",
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "Ocena TMDB rosnąco",
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "Ocena TMDB malejąco",
"components.Discover.DiscoverSliderEdit.deletefail": "Nie udało się usunąć suwaka.",
"components.Discover.DiscoverSliderEdit.deletesuccess": "Pomyślnie usunięto suwak.",
"components.Discover.DiscoverSliderEdit.enable": "Przełącz widoczność",
"components.Discover.DiscoverSliderEdit.remove": "Usuń",
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "Data premiery rosnąco",
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "Data premiery malejąco",
"components.Discover.DiscoverTv.sortPopularityAsc": "Popularność rosnąco",
"components.Discover.DiscoverTv.sortPopularityDesc": "Popularność malejąco",
"components.Discover.DiscoverTv.sortTitleAsc": "Tytuł (A-Z) rosnąco",
"components.Discover.DiscoverTv.sortTitleDesc": "Tytuł (Z-A) malejąco",
"components.Discover.DiscoverTv.sortTmdbRatingDesc": "Ocena TMDB malejąco",
"components.Discover.FilterSlideover.clearfilters": "Wyczyść aktywne filtry",
"components.Discover.FilterSlideover.filters": "Filtry",
"components.Discover.FilterSlideover.firstAirDate": "Data pierwszego wyemitowania",
"components.Discover.FilterSlideover.from": "Od",
"components.Discover.FilterSlideover.genres": "Gatunki",
"components.Discover.FilterSlideover.keywords": "Słowa kluczowe",
"components.Discover.FilterSlideover.ratingText": "Oceny między {minValue} a {maxValue}",
"components.Discover.CreateSlider.providetmdbkeywordid": "Podaj ID słowa kluczowego TMDB",
"components.Discover.CreateSlider.searchKeywords": "Wyszukaj słowa kluczowe…",
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "Data wydania rosnąco",
"components.Discover.DiscoverTv.discovertv": "Seriale",
"components.Discover.DiscoverTv.sortTmdbRatingAsc": "Ocena TMDB rosnąco",
"components.Discover.DiscoverTvKeyword.keywordSeries": "Seriale: {keywordTitle}",
"components.Discover.FilterSlideover.originalLanguage": "Oryginalny język",
"components.Discover.FilterSlideover.releaseDate": "Data wydania",
"components.Discover.FilterSlideover.runtime": "Długość",
"components.Discover.FilterSlideover.runtimeText": "{minValue}-{maxValue} minut trwania",
"components.Discover.FilterSlideover.streamingservices": "Serwisy streamingowe",
"components.Discover.FilterSlideover.studio": "Studio",
"components.Discover.FilterSlideover.tmdbuservotecount": "Liczba głosów użytkowników TMDB",
"components.Discover.FilterSlideover.to": "Do",
"components.Discover.FilterSlideover.voteCount": "Liczba głosów między {minValue} a {maxValue}",
"components.Discover.PlexWatchlistSlider.plexwatchlist": "Twoja lista obserwowanych Plex",
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Niedawno dodane",
"components.Discover.createnewslider": "Dodaj nowy suwak",
"components.Discover.customizediscover": "Dostosuj Odkryj",
"components.Discover.PlexWatchlistSlider.emptywatchlist": "Media dodane do twojej <PlexWatchlistSupportLink>listy obserwowanych Plex</PlexWatchlistSupportLink> zostaną wyświetlone tutaj.",
"components.Discover.emptywatchlist": "Media dodane do twojej <PlexWatchlistSupportLink>listy obserwowanych Plex</PlexWatchlistSupportLink> zostaną wyświetlone tutaj.",
"components.Discover.tmdbstudio": "Studio TMDB",
"components.Discover.tmdbtvkeyword": "Słowo kluczowe serialu TMDB",
"components.Discover.tmdbtvgenre": "Gatunek serialu TMDB",
"components.Discover.tmdbsearch": "Wyszukiwanie TMDB"
}

View File

@@ -1256,5 +1256,36 @@
"components.Discover.tmdbmoviestreamingservices": "Serviços de Streaming de Filmes do TMDB",
"components.Discover.FilterSlideover.tmdbuservotecount": "Qtd de Votos de Usuários TMDB",
"components.Discover.FilterSlideover.voteCount": "Qtd the votos entre {minValue} e {maxValue}",
"components.Settings.RadarrModal.tagRequestsInfo": "Adicione automaticamente uma tag extra com o ID de usuário e o nome de exibição do solicitante"
"components.Settings.RadarrModal.tagRequestsInfo": "Adicione automaticamente uma tag extra com o ID de usuário e o nome de exibição do solicitante",
"components.Layout.UserWarnings.emailRequired": "Um endereço de e-mail é necessário.",
"components.Login.credentialerror": "O nome de usuário ou senha está incorreto.",
"components.Login.description": "Já que é sua primeira vez entrando em {applicationName}, você precisa adicionar um e-mail válido.",
"components.Login.host": "URL de {mediaServerName}",
"components.Login.initialsignin": "Conectar",
"components.Login.initialsigningin": "Conectando…",
"components.Login.save": "Adicionar",
"components.Login.saving": "Adicionando…",
"components.Login.signinwithjellyfin": "Use sua conta de {mediaServerName}",
"components.Login.title": "Adicionar E-Mail",
"components.Login.username": "Nome de usuário",
"components.Login.validationEmailFormat": "E-mail inválido",
"components.Login.validationEmailRequired": "Você precisa providenciar um e-mail",
"components.Login.validationemailformat": "E-mail válido necessário",
"components.Login.validationhostformat": "URL válido necessário",
"components.Login.validationusernamerequired": "Nome de usuário necessário",
"components.ManageSlideOver.removearr": "Remover de {arr}",
"components.ManageSlideOver.removearr4k": "Remover de {arr} 4K",
"components.MovieDetails.downloadstatus": "Status de download",
"components.MovieDetails.imdbuserscore": "Avaliação de usuário no IMDB",
"components.MovieDetails.openradarr": "Abrir filme no Radarr",
"components.Settings.Notifications.NotificationsPushover.sound": "Som de notificação",
"components.Login.emailtooltip": "Endereço não precisa ser associado à sua instância de {mediaServerName}.",
"components.Layout.UserWarnings.emailInvalid": "Endereço de e-mail inválido.",
"components.Layout.UserWarnings.passwordRequired": "Uma senha é necessária.",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Padrão do dispositivo",
"components.Login.validationhostrequired": "URL de {mediaServerName} necessário",
"components.MovieDetails.openradarr4k": "Abrir filme em Radarr 4K",
"components.MovieDetails.play": "Reproduzir em {mediaServerName}",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Isto irá remover este {mediaType} de {arr}, incluindo todos os arquivos.",
"components.MovieDetails.play4k": "Reproduzir em 4K em {mediaServerName}"
}

View File

@@ -332,7 +332,7 @@
"components.TvDetails.anime": "Anime",
"components.TvDetails.TvCrew.fullseriescrew": "Equipa Técnica Completa da Série",
"components.TvDetails.TvCast.fullseriescast": "Elenco Completo da Série",
"components.StatusChacker.reloadJellyseerr": "Recarregar",
"components.StatusChacker.reloadOverseerr": "Recarregar",
"components.StatusChacker.newversionavailable": "Atualização de Aplicação",
"components.StatusChacker.newversionDescription": "Jellyseerr foi atualizado! Clique no botão abaixo para recarregar a página.",
"components.StatusBadge.status4k": "4K {status}",

View File

@@ -406,5 +406,37 @@
"components.RequestButton.approve4krequests": "Aprobă {requestCount, plural, o {4K Request} alte {{requestCount} 4K Requests}}",
"components.RequestBlock.lastmodifiedby": "Ultima Dată Modificat de",
"components.RequestBlock.profilechanged": "Profil Calitate",
"components.RequestBlock.requestdate": "Dată Solicitare"
"components.RequestBlock.requestdate": "Dată Solicitare",
"components.Layout.UserWarnings.emailRequired": "Este necesara o adresa de email.",
"components.Layout.UserWarnings.passwordRequired": "Este necesara o parola.",
"components.Login.credentialerror": "Numele de utilizator sau parola sunt incorecte.",
"components.Login.emailtooltip": "Nu este necesar ca adresa ta sa fie asociata cu instanta ta {mediaServerName} .",
"components.Login.save": "Adauga",
"components.Login.signinwithjellyfin": "Foloseste-ti contul de {mediaServerName}",
"components.Login.title": "Adauga email",
"components.Login.username": "Nume utilizator",
"components.Login.validationEmailFormat": "Adresa email invalida",
"components.Login.validationemailformat": "Necesar email valid",
"components.Login.validationhostformat": "Necesar URL valid",
"components.Login.validationhostrequired": "{mediaServerName} URL necesar",
"components.Login.validationusernamerequired": "Nume utilizator necesar",
"components.MovieDetails.downloadstatus": "Status descarcare",
"components.MovieDetails.openradarr": "Deschide film in Radarr",
"components.MovieDetails.openradarr4k": "Deschide film in 4K Radarr",
"components.MovieDetails.play": "Ruleaza pe {mediaServerName}",
"components.MovieDetails.play4k": "Ruleaza 4k pe {mediaServerName}",
"components.RequestButton.declinerequest": "Refuza cerere",
"components.RequestButton.declinerequest4k": "Refuza cerere 4k",
"components.Layout.UserWarnings.emailInvalid": "Adresa de email este invalida.",
"components.Login.description": "Deoarece este prima ta authentificare in {applicationName}, este necesara sa introduci o adresa de email valida.",
"components.Login.initialsigningin": "Se conecteaza…",
"components.Login.saving": "Se adauga…",
"components.RequestButton.approverequest": "Aproba cerere",
"components.RequestButton.approverequest4k": "Aproba cerere 4k",
"components.Login.host": "{mediaServerName} URL",
"components.Login.initialsignin": "Conecteaza-te",
"components.ManageSlideOver.removearr4k": "Elimina din 4K {arr}",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Acesta va elimina ireversibil {mediaType} din {arr}, incluzand toate fisierele asociate.",
"components.Login.validationEmailRequired": "Trebuie sa introduci o adresa email",
"components.ManageSlideOver.removearr": "Elimina din {arr}"
}

View File

@@ -33,7 +33,7 @@
"components.RequestModal.cancel": "Отменить запрос",
"components.RequestModal.extras": "Дополнительно",
"components.RequestModal.numberofepisodes": "# эпизодов",
"components.RequestModal.pendingrequest": "",
"components.RequestModal.pendingrequest": "Ожидающий запрос",
"components.RequestModal.requestCancel": "Запрос на <strong>{title}</strong> отменён.",
"components.RequestModal.requestSuccess": "<strong>{title}</strong> успешно запрошен!",
"components.RequestModal.requestadmin": "Этот запрос будет одобрен автоматически.",
@@ -427,9 +427,9 @@
"components.Settings.RadarrModal.testFirstRootFolders": "Протестировать подключение для загрузки корневых каталогов",
"components.Settings.RadarrModal.loadingrootfolders": "Загрузка корневых каталогов…",
"components.RequestModal.AdvancedRequester.destinationserver": "Сервер-получатель",
"components.RequestList.RequestItem.mediaerror": "Название, связанное с этим запросом, больше недоступно.",
"components.RequestList.RequestItem.mediaerror": "{mediaType} не найдено",
"components.RequestList.RequestItem.failedretry": "Что-то пошло не так при попытке повторить запрос.",
"components.RequestCard.mediaerror": "Название, связанное с этим запросом, больше недоступно.",
"components.RequestCard.mediaerror": "{mediaType} не найдено",
"components.RequestCard.failedretry": "Что-то пошло не так при попытке повторить запрос.",
"components.RequestButton.viewrequest4k": "Посмотреть 4К запрос",
"components.RequestButton.requestmore4k": "Запросить больше в 4К",
@@ -570,7 +570,7 @@
"components.TvDetails.seasons": "{seasonCount, plural, one {# сезон} other {# сезонов}}",
"components.RequestModal.QuotaDisplay.requiredquotaUser": "Этому пользователю необходимо иметь по крайней мере <strong>{seasons}</strong> {seasons, plural, one {запрос на сезоны} other {запроса(ов) на сезоны}} для того, чтобы отправить запрос на этот сериал.",
"components.RequestModal.QuotaDisplay.requiredquota": "Вам необходимо иметь по крайней мере <strong>{seasons}</strong> {seasons, plural, one {запрос на сезоны} other {запроса(ов) на сезоны}} для того, чтобы отправить запрос на этот сериал.",
"components.RequestModal.pending4krequest": "",
"components.RequestModal.pending4krequest": "Ожидающий 4K запрос",
"components.RequestModal.autoapproval": "Автоматическое одобрение",
"i18n.usersettings": "Настройки пользователя",
"i18n.showingresults": "Показываются результаты с <strong>{from}</strong> по <strong>{to}</strong> из <strong>{total}</strong>",
@@ -790,7 +790,7 @@
"components.UserList.importfromplexerror": "Что-то пошло не так при импорте пользователей из Plex.",
"components.UserList.importfrommediaserver": "Импортировать пользователей из {mediaServerName}",
"components.UserList.importfromplex": "Импортировать пользователей из Plex",
"components.UserList.importedfromplex": "{userCount, plural, one {# новый пользователь} other {# новых пользователя(ей)}} успешно импортированы из Plex!",
"components.UserList.importedfromplex": "<strong>{userCount}</strong> {userCount, plural, one {# новый пользователь} other {# новых пользователя(ей)}} успешно импортированы из Plex!",
"components.UserList.edituser": "Изменить разрешения пользователя",
"components.UserList.displayName": "Отображаемое имя",
"components.UserList.deleteconfirm": "Вы уверены, что хотите удалить этого пользователя? Все данные о его запросах будут удалены без возможности восстановления.",
@@ -1117,7 +1117,7 @@
"components.MovieDetails.digitalrelease": "Цифровой релиз",
"components.MovieDetails.physicalrelease": "Физический релиз",
"components.Settings.SettingsMain.toastSettingsFailure": "Что-то пошло не так при сохранении настроек.",
"components.Settings.SettingsMain.trustProxyTip": "Разрешить Overserr правильно регистрировать IP-адреса клиентов за прокси-сервером",
"components.Settings.SettingsMain.trustProxyTip": "Разрешить Jellyseerr правильно регистрировать IP-адреса клиентов за прокси-сервером",
"components.Settings.experimentalTooltip": "Включение этого параметра может привести к неожиданному поведению приложения",
"components.Settings.advancedTooltip": "Неправильная настройка этого параметра может привести к нарушению функциональности",
"components.Settings.externalUrl": "Внешний URL-адрес",
@@ -1131,7 +1131,7 @@
"components.Settings.validationApiKey": "Вы должны предоставить ключ API",
"components.TitleCard.mediaerror": "{mediaType} не найдено",
"components.TitleCard.tmdbid": "TMDB ID",
"components.Settings.restartrequiredTooltip": "Чтобы изменения этого параметра вступили в силу, необходимо перезапустить Overserr",
"components.Settings.restartrequiredTooltip": "Чтобы изменения этого параметра вступили в силу, необходимо перезапустить Jellyseerr",
"components.ManageSlideOver.alltime": "Все время",
"components.ManageSlideOver.plays": "<strong>{playCount, number}</strong> {playCount, plural, one {просмотр} other {просмотров}}",
"components.Settings.Notifications.NotificationsGotify.agentenabled": "Включить агент",
@@ -1214,13 +1214,13 @@
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending": "Отправка тестового уведомления Gotify…",
"components.Settings.SettingsMain.cacheImages": "Включить кэширование изображений",
"components.Settings.SettingsMain.generalsettings": "Общие настройки",
"components.Settings.SettingsMain.generalsettingsDescription": "Настройте глобальные параметры и параметры по умолчанию для Overserr.",
"components.Settings.SettingsMain.generalsettingsDescription": "Настройте глобальные параметры и параметры по умолчанию для Jellyseerr.",
"components.Settings.SettingsMain.hideAvailable": "Скрыть доступные медиа",
"components.Settings.SettingsMain.regionTip": "Фильтровать контент по региональной доступности",
"components.Settings.SettingsMain.toastApiKeyFailure": "Что-то пошло не так при создании нового ключа API.",
"components.Settings.SettingsMain.locale": "Язык приложения",
"components.Settings.SettingsMain.originallanguage": "Регион поиска",
"components.Settings.tautulliSettingsDescription": "При желании настройте параметры для вашего сервера Tautulli. Overserr извлекает данные истории просмотров Plex из Tautulli.",
"components.Settings.tautulliSettingsDescription": "При желании настройте параметры для вашего сервера Tautulli. Jellyseerr извлекает данные истории просмотров Plex из Tautulli.",
"components.Settings.toastTautulliSettingsFailure": "Что-то пошло не так при сохранении настроек Tautulli.",
"components.Settings.toastTautulliSettingsSuccess": "Настройки Tautulli успешно сохранены!",
"components.Settings.validationUrlBaseTrailingSlash": "База URL не должна заканчиваться косой чертой",
@@ -1241,7 +1241,7 @@
"components.Settings.Notifications.NotificationsGotify.validationTypes": "Вы должны выбрать как минимум один тип уведомления",
"components.Settings.Notifications.NotificationsGotify.validationUrlRequired": "Вы должны указать действующий URL",
"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash": "URL не должен заканчиваться слешем",
"components.Settings.SettingsJobsCache.imagecacheDescription": "Если включено, Overserr будет проксировать и кэшировать изображения из предварительно настроенных внешних источников. Кэшированные изображения сохраняются в папку конфигурации. Вы можете найти файлы в <code>{appDataPath}/cache/images</code>.",
"components.Settings.SettingsJobsCache.imagecacheDescription": "Если включено, Jellyseerr будет проксировать и кэшировать изображения из предварительно настроенных внешних источников. Кэшированные изображения сохраняются в папку конфигурации. Вы можете найти файлы в <code>{appDataPath}/cache/images</code>.",
"components.Settings.tautulliSettings": "Настройки Tautulli",
"components.StatusBadge.seasonepisodenumber": "S{seasonNumber}E{episodeNumber}",
"components.Discover.customizediscover": "Настроить Обнаружение",
@@ -1256,5 +1256,93 @@
"components.Selector.showless": "Показать меньше",
"components.Selector.showmore": "Показать больше",
"components.Settings.SettingsJobsCache.imagecachesize": "Размер кэша",
"components.Settings.validationUrlBaseLeadingSlash": "Базовый URL должен начинаться с косой черты"
"components.Settings.validationUrlBaseLeadingSlash": "Базовый URL должен начинаться с косой черты",
"components.Layout.UserWarnings.emailRequired": "Требуется указать email адрес.",
"components.Layout.UserWarnings.passwordRequired": "Требуется указать пароль.",
"components.Login.emailtooltip": "Адрес не обязательно должен быть связан с вашим {mediaServerName} сервером.",
"components.Login.initialsignin": "Подключиться",
"components.Login.initialsigningin": "Подключение…",
"components.Login.save": "Добавить",
"components.Login.saving": "Добавление…",
"components.Login.signinwithjellyfin": "Используйте свой {mediaServerName} аккаунт",
"components.Login.host": "{mediaServerName} URL",
"components.Login.username": "Имя пользователя",
"components.Login.validationEmailFormat": "Неверный email",
"components.Login.validationemailformat": "Необходим корректный email",
"components.Login.validationhostformat": "Необходим корректный URL",
"components.Login.validationhostrequired": "Необходим {mediaServerName} URL",
"components.Login.validationusernamerequired": "Необходимо имя пользователя",
"components.ManageSlideOver.removearr": "Удалить из {arr}",
"components.ManageSlideOver.removearr4k": "Удалить из 4К {arr}",
"components.MovieDetails.imdbuserscore": "Оценка пользователей IMDB",
"components.MovieDetails.openradarr": "Открыть фильм в Radarr",
"components.MovieDetails.play": "Запустить на {mediaServerName}",
"components.MovieDetails.play4k": "Запустить 4К на {mediaServerName}",
"components.Settings.RadarrModal.tagRequests": "Тег запросов",
"components.Layout.UserWarnings.emailInvalid": "Неверный email адрес.",
"components.Settings.SonarrModal.seriesType": "Тип сериала",
"components.Discover.FilterSlideover.voteCount": "Количество голосов от {minValue} до {maxValue}",
"components.Login.validationEmailRequired": "Вы должны указать адрес электронной почты",
"components.Settings.Notifications.userEmailRequired": "Требуется email пользователя",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Сканировать недавно добавленное в Jellyfin",
"components.Discover.tmdbmoviestreamingservices": "Сервисы потоковой передачи фильмов TMDB",
"components.Discover.tmdbtvstreamingservices": "Сервисы потоковой передачи сериалов TMDB",
"components.Login.description": "Поскольку вы впервые входите в систему {ApplicationName}, вам необходимо добавить адрес электронной почты.",
"components.Settings.Notifications.NotificationsPushover.sound": "Звук уведомлений",
"components.Settings.RadarrModal.tagRequestsInfo": "Автодобавление тега с именем и ID пользователя, отправившего запрос",
"components.Settings.SonarrModal.animeSeriesType": "Тип аниме",
"components.Discover.FilterSlideover.tmdbuservotecount": "Количество голосов от пользователей TMDB",
"components.Login.credentialerror": "Введено неверное имя пользователя или пароль.",
"components.Login.title": "Добавить email",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* Это приведет к необратимому удалению {MediaType} из {arr}, включая все файлы.",
"components.Settings.SettingsAbout.supportjellyseerr": "Поддержать Jellyseerr",
"components.Settings.SonarrModal.tagRequests": "Тег запросов",
"components.MovieDetails.downloadstatus": "Статус загрузки",
"components.MovieDetails.openradarr4k": "Открыть фильм в 4К Radarr",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Устройство по умолчанию",
"components.Settings.SettingsJobsCache.jellyfin-full-scan": "Сканировать всю библиотеку Jellyfin",
"components.Settings.SettingsJobsCache.availability-sync": "Синхронизировать доступность медиа",
"components.Settings.jellyfinSettingsFailure": "Что-то пошло не так во время сохранения настроек {mediaServerName}.",
"components.Settings.jellyfinSettingsSuccess": "Настройки {mediaServerName} успешно сохранены!",
"components.Settings.jellyfinlibraries": "Библиотеки {mediaServerName}",
"components.Settings.jellyfinlibrariesDescription": "Библиотеки {mediaServerName} проверяются на наличие заголовков. Нажмите кнопку ниже, если в списке не хватает библиотек.",
"components.Settings.jellyfinsettings": "Настройки {mediaServerName}",
"components.Settings.internalUrl": "Внутренний URL-адрес",
"components.Settings.SonarrModal.tagRequestsInfo": "Автодобавление тега с именем и ID пользователя, отправившего запрос",
"components.Settings.jellyfinSettings": "Настройки {mediaServerName}",
"components.Settings.jellyfinSettingsDescription": "Необязательно настраивать внутреннюю и внешнюю конечные точки для вашего сервера {mediaServerName}. В большинстве случаев внешний URL-адрес отличается от внутреннего. Пользовательский URL-адрес для сброса пароля также может быть задан для входа в систему {mediaServerName}, на случай, если вы хотите перенаправить на другую страницу для сброса пароля.",
"components.Settings.jellyfinsettingsDescription": "Настройте свой {mediaServerName} сервер. {mediaServerName} отсканирует ваши библиотеки, чтобы увидеть, какие библиотеки доступны.",
"components.Settings.manualscanJellyfin": "Сканировать библиотеки вручную",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.Settings.syncJellyfin": "Синхронизировать библиотеки",
"components.Settings.syncing": "Синхронизация",
"components.Settings.timeout": "Время ожидания",
"components.Setup.signin": "Войти",
"components.Setup.signinWithPlex": "Используйте свой Plex аккаунт",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong> успешно удален из списка наблюдения!",
"components.TitleCard.watchlistError": "Что-то пошло не так, попробуйте еще раз.",
"components.TvDetails.play": "Запустить в {mediaServerName}",
"components.TvDetails.play4k": "Запустить 4К в {mediaServerName}",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {userCount, plural, one {# новый пользователь} other {# новых пользователя(ей)}} успешно импортированы из {mediaServerName}!",
"components.UserList.importfromJellyfin": "Добавить пользователей из {mediaServerName}",
"components.UserList.noJellyfinuserstoimport": "Нет пользователей {mediaServerName} для импорта.",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "Пользователь {mediaServerName}",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Сохранение…",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Звук уведомлений",
"i18n.collection": "Коллекция",
"components.Setup.configuremediaserver": "Настройте медиасервер",
"components.UserList.importfromJellyfinerror": "Что-то пошло не так при импорте пользователей из {mediaServerName}.",
"components.UserList.newJellyfinsigninenabled": "Параметр <strong>Включить новый вход в {mediaServerName}</strong> в настоящее время включен. Пользователей {mediaServerName} с доступом к библиотеке не нужно импортировать для входа.",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "Электронная почта",
"components.UserProfile.localWatchlist": "Список наблюдения {username}",
"components.Settings.manualscanDescriptionJellyfin": "Обычно это выполняется только раз в 24 часа. Jellyseerr будет более настойчиво проверять недавно добавленный сервер {mediaServerName}. Если вы впервые настраиваете Jellyseerr, то рекомендуем однократное полное сканирование библиотеки!",
"components.TitleCard.watchlistCancel": "наблюдение за <strong>{title}</strong> отменено.",
"components.Settings.saving": "Сохранение…",
"components.TitleCard.addToWatchList": "Добавить в список наблюдения",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong> успешно добавлен в список наблюдения!",
"components.Settings.save": "Сохранить изменения",
"components.Setup.signinWithJellyfin": "Используйте свой {mediaServerName} аккаунт",
"components.UserList.mediaServerUser": "Пользователь {mediaServerName}",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Сохранить изменения",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Устройство по умолчанию"
}

57
src/i18n/locale/sl.json Normal file
View File

@@ -0,0 +1,57 @@
{
"components.Discover.CreateSlider.editsuccess": "Urejen drsnik in shranjene nastavitve prilagajanja odkrivanja.",
"components.CollectionDetails.numberofmovies": "{count} film/ov",
"components.Discover.CreateSlider.slidernameplaceholder": "Ime drsnika",
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "Premiera ↓",
"components.AppDataWarning.dockerVolumeMissingDescription": "Pripenjanje nosilca <code>{appDataPath}</code> ni bilo pravilno konfigurirano. Vsi podatki bodo izbrisani, ko se vsebnik zaustavi ali znova zažene.",
"components.Discover.DiscoverMovies.sortPopularityDesc": "Priljubljenost ↑",
"components.AirDateBadge.airsrelative": "Predvajanje {relativeTime}",
"components.CollectionDetails.overview": "Pregled",
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {# Active Filter} drugo {# Active Filters}}",
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "Ocena TMDB ↓",
"components.AirDateBadge.airedrelative": "Predvajano {relativeTime}",
"components.Discover.CreateSlider.searchStudios": "Iskanje studiev …",
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "Datum izdaje ↑",
"components.Discover.CreateSlider.providetmdbnetwork": "Navedite ID omrežja TMDB",
"components.Discover.CreateSlider.addfail": "Novega drsnika ni bilo mogoče ustvariti.",
"components.CollectionDetails.requestcollection": "Zahtevaj zbirko",
"components.Discover.DiscoverMovieGenre.genreMovies": "Filmi: {genre}",
"components.Discover.DiscoverMovieLanguage.languageMovies": "Filmi: {language}",
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {# Active Filter} other {# Active Filters}}",
"components.Discover.DiscoverMovies.sortPopularityAsc": "Priljubljenost ↓",
"components.Discover.CreateSlider.needresults": "Imeti morate vsaj 1 rezultat.",
"components.Discover.CreateSlider.addcustomslider": "Ustvari drsnik po meri",
"components.Discover.DiscoverTv.sortPopularityAsc": "Priljubljenost ↓",
"components.Discover.CreateSlider.editSlider": "Uredi drsnik",
"components.Discover.DiscoverTv.sortTitleAsc": "Naslov (a-ž) ↓",
"components.Discover.CreateSlider.validationDatarequired": "Navesti morate vrednost podatkov.",
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "Premiera ↑",
"components.Discover.DiscoverTv.discovertv": "Serije",
"components.Discover.DiscoverSliderEdit.deletefail": "Drsnika ni bilo mogoče izbrisati.",
"components.Discover.CreateSlider.providetmdbstudio": "Navedite ID studia v TMDB",
"components.Discover.DiscoverMovies.sortTitleDesc": "Naslov (a-ž) ↑",
"components.Discover.DiscoverStudio.studioMovies": "{studio} filmi",
"components.Discover.DiscoverTv.sortPopularityDesc": "Priljubljenost ↑",
"components.Discover.CreateSlider.searchGenres": "Išči žanre …",
"components.Discover.CreateSlider.editfail": "Drsnika ni bilo mogoče urediti.",
"components.Discover.CreateSlider.starttyping": "Tipkajte za iskanje.",
"components.Discover.DiscoverSliderEdit.enable": "Preklopi vidnost",
"components.Discover.CreateSlider.addSlider": "Dodaj drsnik",
"components.CollectionDetails.requestcollection4k": "Zahtevaj zbirko 4K",
"components.Discover.CreateSlider.providetmdbsearch": "Vnesite iskalno poizvedbo",
"components.Discover.DiscoverNetwork.networkSeries": "{network} serije",
"components.Discover.CreateSlider.providetmdbkeywordid": "Navedite ID ključne besede TMDB",
"components.Discover.DiscoverMovieKeyword.keywordMovies": "Filmi: {keywordTitle}",
"components.Discover.CreateSlider.validationTitlerequired": "Navesti morate naslov.",
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "Datum izdaje ↓",
"components.Discover.CreateSlider.nooptions": "Ni zadetkov.",
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "Ocena TMDB ↑",
"components.Discover.CreateSlider.searchKeywords": "Iskanje po ključnih besedah …",
"components.Discover.CreateSlider.addsuccess": "Ustvarjen nov drsnik in shranjene nastavitve prilagajanja odkrivanja.",
"components.Discover.DiscoverSliderEdit.deletesuccess": "Drsnik je bil uspešno izbrisan.",
"components.Discover.DiscoverMovies.discovermovies": "Filmi",
"components.Discover.DiscoverMovies.sortTitleAsc": "Naslov (a-ž) ↓",
"components.Discover.CreateSlider.providetmdbgenreid": "Navedite ID žanra TMDB",
"components.Discover.DiscoverTv.sortTitleDesc": "Naslov (a-ž) ↑",
"components.Discover.DiscoverSliderEdit.remove": "Odstrani"
}

View File

@@ -1092,7 +1092,7 @@
"components.RequestList.RequestItem.tvdbid": "TheTVDB ID",
"components.Settings.SettingsJobsCache.plex-watchlist-sync": "Synkronisering av Plex Watchlist",
"components.Settings.advancedTooltip": "Om du konfigurerar den här inställningen felaktigt kan det leda till att funktionerna inte fungerar",
"components.Settings.restartrequiredTooltip": "Overseerr måste startas om för att ändringarna i den här inställningen ska träda i kraft",
"components.Settings.restartrequiredTooltip": "Jellyseerr måste startas om för att ändringarna i den här inställningen ska träda i kraft",
"components.TvDetails.reportissue": "Rapportera ett problem",
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries": "Begär automatiskt serier",
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip": "Begär automatiskt serier på din <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>",
@@ -1103,7 +1103,7 @@
"components.StatusBadge.playonplex": "Spela upp på Plex",
"components.TitleCard.tvdbid": "TheTVDB ID",
"components.Settings.SettingsLogs.viewdetails": "Visa detaljer",
"components.Settings.SettingsJobsCache.imagecacheDescription": "När det är aktiverat i inställningarna kommer Overseerr att göra proxy- och cache-bilder från förkonfigurerade externa källor. Cachade bilder sparas i din konfigurationsmapp. Du hittar filerna i <code>{appDataPath}/cache/images</code>.",
"components.Settings.SettingsJobsCache.imagecacheDescription": "När det är aktiverat i inställningarna kommer Jellyseerrr att göra proxy- och cache-bilder från förkonfigurerade externa källor. Cachade bilder sparas i din konfigurationsmapp. Du hittar filerna i <code>{appDataPath}/cache/images</code>.",
"components.TitleCard.cleardata": "Rensa data",
"components.TitleCard.mediaerror": "{mediaType} Hittades inte",
"components.TvDetails.rtcriticsscore": "Rotten Tomatoes Tomatometer",
@@ -1183,7 +1183,7 @@
"components.Settings.SettingsMain.csrfProtectionTip": "Ställ in extern API-åtkomst till skrivskyddad (kräver HTTPS)",
"components.Settings.SettingsMain.general": "Allmänt",
"components.Settings.SettingsMain.generalsettings": "Generella inställningar",
"components.Settings.SettingsMain.generalsettingsDescription": "Konfigurera globala och standard-inställningar för Overseerr.",
"components.Settings.SettingsMain.generalsettingsDescription": "Konfigurera globala och standard-inställningar för Jellyseerr.",
"components.Settings.SettingsMain.locale": "Visningsspråk",
"components.Settings.SettingsMain.originallanguage": "Upptäck språk",
"components.Settings.SettingsMain.originallanguageTip": "Filtrera innehållet efter originalspråk",
@@ -1192,7 +1192,7 @@
"components.Settings.SettingsMain.regionTip": "Filtrera innehållet efter regional tillgänglighet",
"components.Settings.SettingsMain.toastApiKeyFailure": "Något gick fel när du genererade en ny API-nyckel.",
"components.Settings.SettingsMain.toastApiKeySuccess": "Ny API-nyckel genererades framgångsrikt!",
"components.Settings.SettingsMain.trustProxyTip": "Tillåt Overseerr att korrekt registrera klienternas IP-adresser bakom en proxy",
"components.Settings.SettingsMain.trustProxyTip": "Tillåt Jellyseerr att korrekt registrera klienternas IP-adresser bakom en proxy",
"components.Discover.resetwarning": "Återställer alla skjutreglage till standardvärdet. Detta raderar också alla anpassade skjutreglage!",
"components.Discover.stopediting": "Sluta redigera",
"components.Discover.tmdbmoviegenre": "TMDB filmgenre",

101
src/i18n/locale/tr.json Normal file
View File

@@ -0,0 +1,101 @@
{
"components.Discover.DiscoverTv.sortTmdbRatingAsc": "TMBD Derecelendirmesi (Artan)",
"components.Discover.moviegenres": "Film Türleri",
"components.Discover.CreateSlider.editsuccess": "Gösterge düzenlendi ve keşfetin özelleştirme ayarları kaydedildi.",
"components.Discover.FilterSlideover.studio": "Stüdyo",
"components.CollectionDetails.numberofmovies": "{count} Filmler",
"components.Discover.PlexWatchlistSlider.emptywatchlist": "<PlexWatchlistSupportLink>Plex İzleme Listenize</PlexWatchlistSupportLink> eklenen içerikler burada gözükeceklerdir.",
"components.Discover.CreateSlider.slidernameplaceholder": "Akış Göstergesinin İsmi",
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Yakın Zamanda Eklenenler",
"components.Discover.FilterSlideover.keywords": "Anahtar Kelimeler",
"components.Discover.FilterSlideover.ratingText": "{minValue} ile {maxValue} arasında ki değerlendirmeler",
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "İlk Yayınlanma Tarihi (Yeni)",
"components.AppDataWarning.dockerVolumeMissingDescription": "Bağlanmış <code>{appDataPath}</code> dizini düzgün bir şekilde yapılandırılmamış. Tüm veriler konteyner yeniden başlatıldığında veya durdurulduğunda temizlenecektir.",
"components.Discover.DiscoverTvKeyword.keywordSeries": "{keywordTitle} Diziler",
"components.Discover.DiscoverMovies.sortPopularityDesc": "Popülerlik (Azalan)",
"components.Discover.StudioSlider.studios": "Stüdyolar",
"components.AirDateBadge.airsrelative": "Yayınlanıyor {relativeTime}",
"components.Discover.DiscoverTv.sortTmdbRatingDesc": "TMBD Derecelendirmesi (Azalan)",
"components.Discover.customizediscover": "Keşfet'i Özelleştir",
"components.Discover.emptywatchlist": "<PlexWatchlistSupportLink>Plex İzleme Listenize</PlexWatchlistSupportLink> eklenen içerikler burada gözükeceklerdir.",
"components.Discover.populartv": "Popüler Diziler",
"components.CollectionDetails.overview": "Kısa Özet",
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {# Active Filter} other {# Active Filters}}",
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "TMBD Derecelendirmesi (Artan)",
"components.Discover.DiscoverTvGenre.genreSeries": "{genre} Diziler",
"components.AirDateBadge.airedrelative": "Yayınlandı {relativeTime}",
"components.Discover.FilterSlideover.clearfilters": "Aktif Filtreleri Temizle",
"components.Discover.CreateSlider.searchStudios": "Stüdyolarda Ara.…",
"components.Discover.DiscoverMovies.sortReleaseDateDesc": ıkış Tarihi (Eski)",
"components.Discover.CreateSlider.providetmdbnetwork": "Bir TMBD Servis Sağlayıcı ID'si seç",
"components.Discover.MovieGenreSlider.moviegenres": "Film Türleri",
"components.Discover.networks": "TV Ağları",
"components.Discover.CreateSlider.addfail": "Gösterge oluşturulamadı.",
"components.CollectionDetails.requestcollection": "Koleksiyonu İstet",
"components.Discover.TvGenreSlider.tvgenres": "Dizi Türleri",
"components.Discover.DiscoverMovieGenre.genreMovies": "{genre} Filmler",
"components.Discover.DiscoverMovieLanguage.languageMovies": "{language} Filmler",
"components.Discover.TvGenreList.seriesgenres": "Dizi Türleri",
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {# Active Filter} other {# Active Filters}}",
"components.Discover.DiscoverTvLanguage.languageSeries": "{language} Diziler",
"components.Discover.DiscoverMovies.sortPopularityAsc": "Popülerlik (Artan)",
"components.Discover.NetworkSlider.networks": "TV Ağları",
"components.Discover.FilterSlideover.streamingservices": "Yayın Hizmetleri",
"components.Discover.CreateSlider.needresults": "Seçtiğin etiketlerin en azından 1 adet sonuç döndürmelidir.",
"components.Discover.popularmovies": "Popüler Filmler",
"components.Discover.FilterSlideover.activefilters": "{count, plural, one {# Active Filter} other {# Active Filters}}",
"components.Discover.plexwatchlist": "İzleme Listeniz",
"components.Discover.CreateSlider.addcustomslider": "Özel Akış Göstergesi Oluştur",
"components.Discover.FilterSlideover.tmdbuserscore": "TMBD Kullanıcı Skoru",
"components.Discover.DiscoverTv.sortPopularityAsc": "Popülerlik (Artan)",
"components.Discover.CreateSlider.editSlider": "Akış Göstergesini düzenle",
"components.Discover.DiscoverTv.sortTitleAsc": "İsim (A-Z) (Baştan)",
"components.Discover.CreateSlider.validationDatarequired": "Bir veri girdisi sağlamalısın.",
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "İlk Yayınlanma Tarihi (Eski)",
"components.Discover.DiscoverWatchlist.discoverwatchlist": "İzleme Listeniz",
"components.Discover.FilterSlideover.releaseDate": ıkış Tarihi",
"components.Discover.DiscoverTv.discovertv": "Diziler",
"components.Discover.recentlyAdded": "Yakın Zamanda Eklenenler",
"components.Discover.DiscoverSliderEdit.deletefail": "Gösterge silinemedi.",
"components.Discover.CreateSlider.providetmdbstudio": "Bir TMBD Stüdyo ID'si seç",
"components.Discover.FilterSlideover.runtime": "Yayım Süresi",
"components.Discover.FilterSlideover.from": "Tarafından",
"components.Discover.DiscoverMovies.sortTitleDesc": "İsim (Z-A) (Sondan)",
"components.Discover.DiscoverStudio.studioMovies": "{studio} Filmleri",
"components.Discover.DiscoverTv.sortPopularityDesc": "Popülerlik (Azalan)",
"components.Discover.CreateSlider.searchGenres": "Türlerde ara…",
"components.Discover.CreateSlider.editfail": "Gösterge düzenlenirken hata oluştu.",
"components.Discover.CreateSlider.starttyping": "Aramak için yazmaya başla.",
"components.Discover.createnewslider": "Yeni Akış Göstergesi Oluştur",
"components.Discover.FilterSlideover.filters": "Filtreler",
"components.Discover.DiscoverWatchlist.watchlist": "Plex İzleme Listen",
"components.Discover.discover": "Keşfet",
"components.Discover.DiscoverSliderEdit.enable": "Görünürlüğü Değiştir",
"components.Discover.CreateSlider.addSlider": "Akış Göstergesi Ekle",
"components.CollectionDetails.requestcollection4k": "Koleksiyonu 4K'da İstet",
"components.Discover.FilterSlideover.firstAirDate": "İlk Yayın Tarihi",
"components.Discover.CreateSlider.providetmdbsearch": "Bir arama sorgusu girin",
"components.Discover.DiscoverNetwork.networkSeries": "{network} Dizileri",
"components.Discover.CreateSlider.providetmdbkeywordid": "Bir TMBD Anahtar Kelime ID'si seç",
"components.Discover.DiscoverMovieKeyword.keywordMovies": "{keywordTitle} Filmler",
"components.Discover.FilterSlideover.runtimeText": "{minValue}-{maxValue} dakika yayım süresi",
"components.Discover.CreateSlider.validationTitlerequired": "Bir başlık girdisi sağlamalısın.",
"components.Discover.PlexWatchlistSlider.plexwatchlist": "İzleme Listeniz",
"components.Discover.DiscoverMovies.sortReleaseDateAsc": ıkış Tarihi (Yeni)",
"components.Discover.FilterSlideover.genres": "Türler",
"components.Discover.FilterSlideover.originalLanguage": "Orjinal Dili",
"components.Discover.CreateSlider.nooptions": "Sonuç yok.",
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "TMBD Derecelendirmesi (Azalan)",
"components.Discover.CreateSlider.searchKeywords": "Anahtar Kelimelerde ara…",
"components.Discover.FilterSlideover.tmdbuservotecount": "TMBD Oy Kullanan Kullanıcı Sayısı",
"components.Discover.CreateSlider.addsuccess": "Yeni gösterge oluşturuldu ve keşfetin özelleştirme ayarları kaydedildi.",
"components.Discover.DiscoverSliderEdit.deletesuccess": "Gösterge başarıyla silindi.",
"components.Discover.DiscoverMovies.discovermovies": "Filmler",
"components.Discover.MovieGenreList.moviegenres": "Film Türleri",
"components.Discover.DiscoverMovies.sortTitleAsc": "İsim (A-Z) (Baştan)",
"components.Discover.FilterSlideover.voteCount": "{minValue} ile {maxValue} sayıları arasında oya sahip olanlar",
"components.Discover.CreateSlider.providetmdbgenreid": "Bir TMBD Tür ID'si seç",
"components.Discover.DiscoverTv.sortTitleDesc": "İsim (Z-A) (Sondan)",
"components.Discover.recentrequests": "Yakın Vakitteki İstekler",
"components.Discover.DiscoverSliderEdit.remove": "Kaldır"
}

View File

@@ -397,7 +397,7 @@
"components.UserProfile.UserSettings.UserPasswordChange.password": "密码设置",
"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "你无权设置此用户的密码。",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "你的帐户目前没有设置密码。在下方配置密码,使你能够作为“本地用户”登录。",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "此用户帐户目前没有设置密码。在下方配置密码,使该帐户能够作为“本地用户”登录。",
"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "此用户帐户目前没有设置密码。配置下面的密码以使此帐户能够作为“本地用户”登录。",
"components.UserProfile.UserSettings.UserPasswordChange.newpassword": "新密码",
"components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "当前的密码",
"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "确认密码",
@@ -766,14 +766,14 @@
"components.RequestButton.viewrequest": "查看请求",
"components.RequestButton.requestmore4k": "再提交 4K 请求",
"components.RequestButton.requestmore": "提交更多季数的请求",
"components.RequestButton.declinerequests": "拒绝{requestCount, plural, one {请求} other {{requestCount} 个请求}}",
"components.RequestButton.declinerequests": "拒绝{requestCount, plural, one {Request} other {{requestCount} Requests}}",
"components.RequestButton.declinerequest4k": "拒绝 4K 请求",
"components.RequestButton.declinerequest": "拒绝请求",
"components.RequestButton.decline4krequests": "拒绝{requestCount, plural, one { 4K 请求} other { {requestCount} 4K 请求}}",
"components.RequestButton.approverequests": "批准{requestCount, plural, one {请求} other {{requestCount} 个请求}}",
"components.RequestButton.decline4krequests": "拒绝 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}",
"components.RequestButton.approverequests": "批准 {requestCount, plural, one {Request} other {{requestCount} Requests}}",
"components.RequestButton.approverequest4k": "批准 4K 请求",
"components.RequestButton.approverequest": "批准请求",
"components.RequestButton.approve4krequests": "批准{requestCount, plural, one { 4K 请求} other { {requestCount} 4K 请求}}",
"components.RequestButton.approve4krequests": "批准 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}",
"components.RequestBlock.server": "目標服务器",
"components.RequestBlock.seasons": "季数",
"components.RequestBlock.rootfolder": "根目录",
@@ -782,10 +782,10 @@
"components.RegionSelector.regionServerDefault": "默认设置({region}",
"components.RegionSelector.regionDefault": "所有地区",
"components.QuotaSelector.unlimited": "无限",
"components.QuotaSelector.tvRequests": "<quotaUnits>每 {quotaDays} {days} </quotaUnits>{quotaLimit}<quotaUnits> {seasons}</quotaUnits>",
"components.QuotaSelector.tvRequests": "{quotaLimit} <quotaUnits>{seasons} 每 {quotaDays} {days}</quotaUnits>",
"components.QuotaSelector.seasons": "季",
"components.QuotaSelector.movies": "部电影",
"components.QuotaSelector.movieRequests": "<quotaUnits>每 {quotaDays} {days} </quotaUnits>{quotaLimit}<quotaUnits> {movies}</quotaUnits>",
"components.QuotaSelector.movieRequests": "{quotaLimit} <quotaUnits>{movies} 每 {quotaDays} {days}</quotaUnits>",
"components.QuotaSelector.days": "天",
"components.PlexLoginButton.signinwithplex": "登入",
"components.PlexLoginButton.signingin": "登入中…",
@@ -900,7 +900,7 @@
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed": "Gotify 测试通知发送失败。",
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending": "Gotify测试通知发送中…",
"components.Settings.Notifications.enableMentions": "允许提及",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes": "每 {jobScheduleMinutes} 分钟",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes": "每 {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken": "应用 API 令牌",
"components.UserList.newplexsigninenabled": "<strong>允许新的 Plex 用户登录</strong> 设置目前已启用。还没有导入的Plex用户也能登录。",
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed": "Pushover 通知设置保存失败。",
@@ -909,7 +909,7 @@
"components.Settings.RadarrModal.inCinemas": "已上映",
"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip": "从您的<PushbulletSettingsLink>账号设置</PushbulletSettingsLink>获取API令牌",
"components.Settings.SettingsAbout.appDataPath": "数据目录",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "每 {jobScheduleHours} 小时",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "每 {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}",
"components.Settings.tautulliSettings": "Tautulli 设置",
"components.Settings.tautulliSettingsDescription": "关于 Tautulli 服务器的设置。Jellyseerr 会从 Tautulli 获取 Plex 媒体的观看历史记录。",
"components.UserProfile.UserSettings.UserGeneralSettings.discordId": "Discord 用户ID",
@@ -1253,12 +1253,91 @@
"components.Settings.SettingsJobsCache.availability-sync": "同步媒体可用性",
"components.Discover.tmdbmoviestreamingservices": "TMDB 电影流媒体服务",
"components.Discover.tmdbtvstreamingservices": "TMDB 电视流媒体服务",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "每 {jobScheduleSeconds} 秒",
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "每 {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}",
"components.Discover.FilterSlideover.voteCount": "在 {minValue} 和 {maxValue} 之间的评分数",
"components.Settings.RadarrModal.tagRequests": "标签请求",
"components.Settings.RadarrModal.tagRequestsInfo": "自动添加带有请求者的用户 ID 和显示名称的附加标签",
"components.Settings.SonarrModal.tagRequests": "标记请求",
"i18n.collection": "合集",
"components.Discover.FilterSlideover.tmdbuservotecount": "TMDB 用户评分数",
"components.Settings.SonarrModal.tagRequestsInfo": "自动添加带有请求者的用户 ID 和显示名称的附加标签"
"components.Settings.SonarrModal.tagRequestsInfo": "自动添加带有请求者的用户 ID 和显示名称的附加标签",
"components.Layout.UserWarnings.passwordRequired": "需要输入密码。",
"components.Login.emailtooltip": "地址不需要与{mediaServerName}实例相关联。",
"components.Login.host": "{mediaServerName} 的 URL",
"components.Login.initialsignin": "连接",
"components.Login.initialsigningin": "连接中……",
"components.Login.save": "添加",
"components.Login.saving": "添加中……",
"components.Login.signinwithjellyfin": "使用您的{mediaServerName}帐户",
"components.Login.title": "添加邮件",
"components.Login.username": "用户名",
"components.Login.validationEmailFormat": "无效的邮件地址",
"components.Login.validationEmailRequired": "你必须提供一个电子邮件",
"components.Login.validationemailformat": "需要有效的电子邮件",
"components.Login.validationhostformat": "需要有效的URL",
"components.Login.validationusernamerequired": "需要用户名",
"components.ManageSlideOver.manageModalRemoveMediaWarning": "* 这将不可逆地从{arr}中删除{mediaType},包括所有文件。",
"components.ManageSlideOver.removearr4k": "移除4K {arr}",
"components.MovieDetails.downloadstatus": "下载状态",
"components.MovieDetails.imdbuserscore": "IMDB用户评分",
"components.MovieDetails.openradarr": "在Radarr中打开电影",
"components.MovieDetails.play": "播放{mediaServerName}",
"components.MovieDetails.play4k": "播放 4K {mediaServerName}",
"components.Settings.Notifications.NotificationsPushover.sound": "通知声音",
"components.Settings.SettingsJobsCache.jellyfin-full-scan": "Jellyfin全库扫描",
"components.Settings.SonarrModal.seriesType": "系列类型",
"components.Settings.jellyfinSettingsFailure": "保存{mediaServerName}设置时出错。",
"components.Settings.jellyfinSettingsSuccess": "{mediaServerName}设置保存成功!",
"components.Settings.jellyfinlibraries": "{mediaServerName}库",
"components.Settings.jellyfinlibrariesDescription": "库{mediaServerName}用于扫描标题。如果没有列出库,请单击下面的按钮。",
"components.Settings.jellyfinsettings": "{mediaServerName}设置",
"components.Settings.manualscanJellyfin": "手动扫描库",
"components.Settings.menuJellyfinSettings": "{mediaServerName}",
"components.Settings.saving": "保存中……",
"components.Settings.syncJellyfin": "同步库",
"components.Settings.syncing": "同步中",
"components.Settings.timeout": "超时",
"components.Setup.signin": "登录",
"components.Setup.signinWithJellyfin": "使用您的{mediaServerName}帐户",
"components.TitleCard.addToWatchList": "添加到监视列表",
"components.TitleCard.watchlistDeleted": "<strong>{title}</strong>从监视列表中删除成功!",
"components.TitleCard.watchlistError": "出了问题,再试一次。",
"components.TvDetails.play": "在 {mediaServerName} 播放",
"components.TvDetails.play4k": "mediaServerName} 播放 4K",
"components.UserList.importfrommediaserver": "导入{mediaServerName}用户",
"components.UserList.mediaServerUser": "{mediaServerName} 用户",
"components.UserList.noJellyfinuserstoimport": "在{mediaServerName}中没有用户要导入。",
"components.UserList.newJellyfinsigninenabled": "<strong>启用 {mediaServerName} 登录</strong> 设置当前已启用. {mediaServerName} 具有库访问权限的用户不需要导入即可登录。",
"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser": "{mediaServerName} 用户",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "设备默认",
"components.Layout.UserWarnings.emailInvalid": "邮件地址无效。",
"components.Layout.UserWarnings.emailRequired": "需要填写电子邮件地址。",
"components.Login.credentialerror": "用户名或密码错误。",
"components.Login.description": "由于这是您第一次登录{applicationName},您需要添加一个有效的电子邮件地址。",
"components.Login.validationhostrequired": "{mediaServerName} URL是必需的",
"components.ManageSlideOver.removearr": "从{arr}中删除",
"components.MovieDetails.openradarr4k": "在 4K Radarr 中打开电影",
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "设备默认",
"components.Settings.Notifications.userEmailRequired": "获取用户邮箱",
"components.Settings.SettingsAbout.supportjellyseerr": "支持Jellyseerr",
"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan": "Jellyfin最近新增扫描",
"components.Settings.SonarrModal.animeSeriesType": "动漫系列",
"components.Settings.internalUrl": "内部URL",
"components.Settings.jellyfinSettings": "{mediaServerName}设置",
"components.Settings.jellyfinSettingsDescription": "可以为您的{mediaServerName}服务器配置内部和外部端点。在大多数情况下外部URL与内部URL不同。如果你想重定向到不同的密码重置页面也可以为{mediaServerName}登录设置自定义密码重置URL。",
"components.Settings.jellyfinsettingsDescription": "配置{mediaServerName}服务器的设置。{mediaServerName}扫描{mediaServerName}库以查看可用的内容。",
"components.Settings.manualscanDescriptionJellyfin": "正常情况下每24小时只会运行一次。Jellyseerr将更积极地检查您的{mediaServerName}服务器最近添加的内容。如果这是您第一次配置Jellyseerr建议您手动进行一次完整的库扫描!",
"components.Settings.save": "保存更改",
"components.Setup.configuremediaserver": "配置媒体服务器",
"components.Setup.signinWithPlex": "使用您的 Plex 帐户",
"components.TitleCard.watchlistCancel": "<strong>{title}</strong>的监视列表已取消。",
"components.TitleCard.watchlistSuccess": "<strong>{title}</strong>添加到监视列表成功!",
"components.UserList.importfromJellyfin": "导入{mediaServerName}用户",
"components.UserProfile.UserSettings.UserGeneralSettings.email": "电子邮件",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "保存更改",
"components.UserList.importfromJellyfinerror": "导入{mediaServerName}用户时出错。",
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "通知声音",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "保存中……",
"components.UserProfile.localWatchlist": "{username}的监视列表",
"components.UserList.importedfromJellyfin": "<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} 导入成功!"
}

View File

@@ -73,8 +73,8 @@ const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
return import('../i18n/locale/sr.json');
case 'sv':
return import('../i18n/locale/sv.json');
case 'ua':
return import('../i18n/locale/ua.json');
case 'uk':
return import('../i18n/locale/uk.json');
case 'zh-CN':
return import('../i18n/locale/zh_Hans.json');
case 'zh-TW':

View File

@@ -3,7 +3,6 @@ const defaultTheme = require('tailwindcss/defaultTheme');
/** @type {import('tailwindcss').Config} */
module.exports = {
important: true,
mode: 'jit',
content: [
'./node_modules/react-tailwindcss-datepicker-sct/dist/index.esm.js',