Compare commits
33 Commits
feat/disco
...
renovate/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fa267a351 | ||
|
|
4aac491209 | ||
|
|
c2d4c61fae | ||
|
|
a2c25d5e4b | ||
|
|
19461574f2 | ||
|
|
6d82eee656 | ||
|
|
676a8c9764 | ||
|
|
e75351aa05 | ||
|
|
bafd93e952 | ||
|
|
1a6125c47d | ||
|
|
14cf43de26 | ||
|
|
b6fe5ac637 | ||
|
|
36283f214a | ||
|
|
d4ae554400 | ||
|
|
af0bd4ca8b | ||
|
|
107bce2e86 | ||
|
|
c749a0f9af | ||
|
|
d28e13187b | ||
|
|
2dd00481c2 | ||
|
|
5c60ffc567 | ||
|
|
8251c73ffa | ||
|
|
be047427df | ||
|
|
e297d25603 | ||
|
|
89287af096 | ||
|
|
3a593d9d76 | ||
|
|
a45fc86032 | ||
|
|
59dabed380 | ||
|
|
b40ba07a4d | ||
|
|
246887efa1 | ||
|
|
28a2c50495 | ||
|
|
c84ca43074 | ||
|
|
e2771a3011 | ||
|
|
3ea5076053 |
@@ -899,6 +899,78 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "RemiRigal",
|
||||
"name": "RemiRigal",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19256051?v=4",
|
||||
"profile": "https://github.com/RemiRigal",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "j0srisk",
|
||||
"name": "Joseph Risk",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/18372584?v=4",
|
||||
"profile": "http://josephrisk.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Loetwiek",
|
||||
"name": "Loetwiek",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/79059734?v=4",
|
||||
"profile": "https://github.com/Loetwiek",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Fuochi",
|
||||
"name": "Fuochi",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4720478?v=4",
|
||||
"profile": "https://github.com/Fuochi",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "demrich",
|
||||
"name": "David Emrich",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/30092389?v=4",
|
||||
"profile": "https://github.com/demrich",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "maxnatamo",
|
||||
"name": "Max T. Kristiansen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5898152?v=4",
|
||||
"profile": "https://maxtrier.dk",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DamsDev1",
|
||||
"name": "Damien Fajole",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/60252259?v=4",
|
||||
"profile": "https://damsdev.me",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AhmedNSidd",
|
||||
"name": "Ahmed Siddiqui",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/36286128?v=4",
|
||||
"profile": "https://github.com/AhmedNSidd",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"badgeTemplate": "<a href=\"#contributors-\"><img alt=\"All Contributors\" src=\"https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg\"/></a>",
|
||||
|
||||
21
.gitattributes
vendored
21
.gitattributes
vendored
@@ -24,3 +24,24 @@
|
||||
*.woff binary
|
||||
*.pyc binary
|
||||
*.pdf binary
|
||||
|
||||
#
|
||||
## Theses files/directories should be excluded from git archives
|
||||
#
|
||||
|
||||
.husky export-ignore
|
||||
.vscode export-ignore
|
||||
docs export-ignore
|
||||
|
||||
.git* export-ignore
|
||||
*ignore export-ignore
|
||||
*.md export-ignore
|
||||
|
||||
.all-contributorsrc export-ignore
|
||||
.editorconfig export-ignore
|
||||
Dockerfile.local export-ignore
|
||||
docker-compose.yml export-ignore
|
||||
stylelint.config.js export-ignore
|
||||
|
||||
public/os_logo_filled.png export-ignore
|
||||
public/preview.jpg export-ignore
|
||||
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
||||
test:
|
||||
name: Lint & Test Build
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-20.04
|
||||
container: node:16.17-alpine
|
||||
runs-on: ubuntu-22.04
|
||||
container: node:18.18-alpine
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
build_and_push:
|
||||
name: Build & Publish Docker Images
|
||||
if: github.ref == 'refs/heads/develop' && !contains(github.event.head_commit.message, '[skip ci]')
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
name: Send Discord Notification
|
||||
needs: build_and_push
|
||||
if: always() && github.event_name != 'pull_request' && !contains(github.event.head_commit.message, '[skip ci]')
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v3
|
||||
|
||||
2
.github/workflows/preview.yml
vendored
2
.github/workflows/preview.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
build_and_push:
|
||||
name: Build & Publish Docker Preview Images
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
semantic-release:
|
||||
name: Tag and release latest version
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
build-snap:
|
||||
name: Build Snap Package (${{ matrix.architecture }})
|
||||
needs: semantic-release
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
name: Send Discord Notification
|
||||
needs: semantic-release
|
||||
if: always()
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v3
|
||||
|
||||
6
.github/workflows/snap.yaml
vendored
6
.github/workflows/snap.yaml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
jobs:
|
||||
name: Job Check
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
build-snap:
|
||||
name: Build Snap Package (${{ matrix.architecture }})
|
||||
needs: jobs
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
name: Send Discord Notification
|
||||
needs: build-snap
|
||||
if: always() && !contains(github.event.head_commit.message, '[skip ci]')
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Get Build Job Status
|
||||
uses: technote-space/workflow-conclusion-action@v3
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:16.17-alpine AS BUILD_IMAGE
|
||||
FROM node:18.18-alpine AS BUILD_IMAGE
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -7,10 +7,11 @@ ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
|
||||
|
||||
RUN \
|
||||
case "${TARGETPLATFORM}" in \
|
||||
'linux/arm64' | 'linux/arm/v7') \
|
||||
apk add --no-cache python3 make g++ && \
|
||||
ln -s /usr/bin/python3 /usr/bin/python \
|
||||
;; \
|
||||
'linux/arm64' | 'linux/arm/v7') \
|
||||
apk update && \
|
||||
apk add --no-cache python3 make g++ gcc libc6-compat bash && \
|
||||
yarn global add node-gyp \
|
||||
;; \
|
||||
esac
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
@@ -33,7 +34,7 @@ RUN touch config/DOCKER
|
||||
RUN echo "{\"commitTag\": \"${COMMIT_TAG}\"}" > committag.json
|
||||
|
||||
|
||||
FROM node:16.17-alpine
|
||||
FROM node:18.18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:16.17-alpine
|
||||
FROM node:18.18-alpine
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
14
README.md
14
README.md
@@ -11,7 +11,7 @@
|
||||
<a href="https://hosted.weblate.org/engage/overseerr/"><img src="https://hosted.weblate.org/widgets/overseerr/-/overseerr-frontend/svg-badge.svg" alt="Translation status" /></a>
|
||||
<a href="https://github.com/sct/overseerr/blob/develop/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/sct/overseerr"></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-98-orange.svg"/></a>
|
||||
<a href="#contributors-"><img alt="All Contributors" src="https://img.shields.io/badge/all_contributors-106-orange.svg"/></a>
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
</p>
|
||||
|
||||
@@ -200,6 +200,18 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://marcofaggian.com"><img src="https://avatars.githubusercontent.com/u/19221001?v=4?s=100" width="100px;" alt="Marco Faggian"/><br /><sub><b>Marco Faggian</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=marcofaggian" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://nemchik.com/"><img src="https://avatars.githubusercontent.com/u/725456?v=4?s=100" width="100px;" alt="Eric Nemchik"/><br /><sub><b>Eric Nemchik</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=nemchik" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RemiRigal"><img src="https://avatars.githubusercontent.com/u/19256051?v=4?s=100" width="100px;" alt="RemiRigal"/><br /><sub><b>RemiRigal</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=RemiRigal" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://josephrisk.com"><img src="https://avatars.githubusercontent.com/u/18372584?v=4?s=100" width="100px;" alt="Joseph Risk"/><br /><sub><b>Joseph Risk</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=j0srisk" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Loetwiek"><img src="https://avatars.githubusercontent.com/u/79059734?v=4?s=100" width="100px;" alt="Loetwiek"/><br /><sub><b>Loetwiek</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Loetwiek" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Fuochi"><img src="https://avatars.githubusercontent.com/u/4720478?v=4?s=100" width="100px;" alt="Fuochi"/><br /><sub><b>Fuochi</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Fuochi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/demrich"><img src="https://avatars.githubusercontent.com/u/30092389?v=4?s=100" width="100px;" alt="David Emrich"/><br /><sub><b>David Emrich</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=demrich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://maxtrier.dk"><img src="https://avatars.githubusercontent.com/u/5898152?v=4?s=100" width="100px;" alt="Max T. Kristiansen"/><br /><sub><b>Max T. Kristiansen</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=maxnatamo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://damsdev.me"><img src="https://avatars.githubusercontent.com/u/60252259?v=4?s=100" width="100px;" alt="Damien Fajole"/><br /><sub><b>Damien Fajole</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=DamsDev1" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AhmedNSidd"><img src="https://avatars.githubusercontent.com/u/36286128?v=4?s=100" width="100px;" alt="Ahmed Siddiqui"/><br /><sub><b>Ahmed Siddiqui</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=AhmedNSidd" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -3,147 +3,147 @@
|
||||
"vapidPrivate": "tmnslaO8ZWN6bNbSEv_rolPeBTlNxOwCCAHrM9oZz3M",
|
||||
"vapidPublic": "BK_EpP8NDm9waor2zn6_S28o3ZYv4kCkJOfYpO3pt3W6jnPmxrgTLANUBNbbyaNatPnSQ12De9CeqSYQrqWzHTs",
|
||||
"main": {
|
||||
"apiKey": "testkey",
|
||||
"applicationTitle": "Overseerr",
|
||||
"applicationUrl": "",
|
||||
"csrfProtection": false,
|
||||
"cacheImages": false,
|
||||
"defaultPermissions": 32,
|
||||
"defaultQuotas": {
|
||||
"movie": {},
|
||||
"tv": {}
|
||||
},
|
||||
"hideAvailable": false,
|
||||
"localLogin": true,
|
||||
"newPlexLogin": true,
|
||||
"region": "",
|
||||
"originalLanguage": "",
|
||||
"trustProxy": false,
|
||||
"partialRequestsEnabled": true,
|
||||
"locale": "en"
|
||||
"apiKey": "testkey",
|
||||
"applicationTitle": "Overseerr",
|
||||
"applicationUrl": "",
|
||||
"csrfProtection": false,
|
||||
"cacheImages": false,
|
||||
"defaultPermissions": 32,
|
||||
"defaultQuotas": {
|
||||
"movie": {},
|
||||
"tv": {}
|
||||
},
|
||||
"hideAvailable": false,
|
||||
"localLogin": true,
|
||||
"newPlexLogin": true,
|
||||
"region": "",
|
||||
"originalLanguage": "",
|
||||
"trustProxy": false,
|
||||
"partialRequestsEnabled": true,
|
||||
"locale": "en"
|
||||
},
|
||||
"plex": {
|
||||
"name": "Seerr",
|
||||
"ip": "192.168.1.1",
|
||||
"port": 32400,
|
||||
"useSsl": false,
|
||||
"libraries": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Movies",
|
||||
"enabled": true,
|
||||
"type": "movie"
|
||||
}
|
||||
],
|
||||
"machineId": "test"
|
||||
"name": "Seerr",
|
||||
"ip": "192.168.1.1",
|
||||
"port": 32400,
|
||||
"useSsl": false,
|
||||
"libraries": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Movies",
|
||||
"enabled": true,
|
||||
"type": "movie"
|
||||
}
|
||||
],
|
||||
"machineId": "test"
|
||||
},
|
||||
"tautulli": {},
|
||||
"radarr": [],
|
||||
"sonarr": [],
|
||||
"public": {
|
||||
"initialized": true
|
||||
"initialized": true
|
||||
},
|
||||
"notifications": {
|
||||
"agents": {
|
||||
"email": {
|
||||
"enabled": false,
|
||||
"options": {
|
||||
"emailFrom": "",
|
||||
"smtpHost": "",
|
||||
"smtpPort": 587,
|
||||
"secure": false,
|
||||
"ignoreTls": false,
|
||||
"requireTls": false,
|
||||
"allowSelfSigned": false,
|
||||
"senderName": "Overseerr"
|
||||
}
|
||||
},
|
||||
"discord": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": "",
|
||||
"enableMentions": true
|
||||
}
|
||||
},
|
||||
"lunasea": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": ""
|
||||
}
|
||||
},
|
||||
"slack": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": ""
|
||||
}
|
||||
},
|
||||
"telegram": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"botAPI": "",
|
||||
"chatId": "",
|
||||
"sendSilently": false
|
||||
}
|
||||
},
|
||||
"pushbullet": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"accessToken": ""
|
||||
}
|
||||
},
|
||||
"pushover": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"accessToken": "",
|
||||
"userToken": ""
|
||||
}
|
||||
},
|
||||
"webhook": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": "",
|
||||
"jsonPayload": "IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i"
|
||||
}
|
||||
},
|
||||
"webpush": {
|
||||
"enabled": false,
|
||||
"options": {}
|
||||
},
|
||||
"gotify": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"url": "",
|
||||
"token": ""
|
||||
}
|
||||
"agents": {
|
||||
"email": {
|
||||
"enabled": false,
|
||||
"options": {
|
||||
"emailFrom": "",
|
||||
"smtpHost": "",
|
||||
"smtpPort": 587,
|
||||
"secure": false,
|
||||
"ignoreTls": false,
|
||||
"requireTls": false,
|
||||
"allowSelfSigned": false,
|
||||
"senderName": "Overseerr"
|
||||
}
|
||||
},
|
||||
"discord": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": "",
|
||||
"enableMentions": true
|
||||
}
|
||||
},
|
||||
"lunasea": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": ""
|
||||
}
|
||||
},
|
||||
"slack": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": ""
|
||||
}
|
||||
},
|
||||
"telegram": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"botAPI": "",
|
||||
"chatId": "",
|
||||
"sendSilently": false
|
||||
}
|
||||
},
|
||||
"pushbullet": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"accessToken": ""
|
||||
}
|
||||
},
|
||||
"pushover": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"accessToken": "",
|
||||
"userToken": ""
|
||||
}
|
||||
},
|
||||
"webhook": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"webhookUrl": "",
|
||||
"jsonPayload": "IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i"
|
||||
}
|
||||
},
|
||||
"webpush": {
|
||||
"enabled": false,
|
||||
"options": {}
|
||||
},
|
||||
"gotify": {
|
||||
"enabled": false,
|
||||
"types": 0,
|
||||
"options": {
|
||||
"url": "",
|
||||
"token": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": {
|
||||
"plex-recently-added-scan": {
|
||||
"schedule": "0 */5 * * * *"
|
||||
},
|
||||
"plex-full-scan": {
|
||||
"schedule": "0 0 3 * * *"
|
||||
},
|
||||
"radarr-scan": {
|
||||
"schedule": "0 0 4 * * *"
|
||||
},
|
||||
"sonarr-scan": {
|
||||
"schedule": "0 30 4 * * *"
|
||||
},
|
||||
"download-sync": {
|
||||
"schedule": "0 * * * * *"
|
||||
},
|
||||
"download-sync-reset": {
|
||||
"schedule": "0 0 1 * * *"
|
||||
}
|
||||
"plex-recently-added-scan": {
|
||||
"schedule": "0 */5 * * * *"
|
||||
},
|
||||
"plex-full-scan": {
|
||||
"schedule": "0 0 3 * * *"
|
||||
},
|
||||
"radarr-scan": {
|
||||
"schedule": "0 0 4 * * *"
|
||||
},
|
||||
"sonarr-scan": {
|
||||
"schedule": "0 30 4 * * *"
|
||||
},
|
||||
"download-sync": {
|
||||
"schedule": "0 * * * * *"
|
||||
},
|
||||
"download-sync-reset": {
|
||||
"schedule": "0 0 1 * * *"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1273,6 +1273,8 @@ components:
|
||||
type: string
|
||||
userToken:
|
||||
type: string
|
||||
sound:
|
||||
type: string
|
||||
GotifySettings:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1708,6 +1710,9 @@ components:
|
||||
pushoverUserKey:
|
||||
type: string
|
||||
nullable: true
|
||||
pushoverSound:
|
||||
type: string
|
||||
nullable: true
|
||||
telegramEnabled:
|
||||
type: boolean
|
||||
telegramBotUsername:
|
||||
@@ -2861,6 +2866,33 @@ paths:
|
||||
responses:
|
||||
'204':
|
||||
description: Test notification attempted
|
||||
/settings/notifications/pushover/sounds:
|
||||
get:
|
||||
summary: Get Pushover sounds
|
||||
description: Returns valid Pushover sound options in a JSON array.
|
||||
tags:
|
||||
- settings
|
||||
parameters:
|
||||
- in: query
|
||||
name: token
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
nullable: false
|
||||
responses:
|
||||
'200':
|
||||
description: Returned Pushover settings
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
/settings/notifications/gotify:
|
||||
get:
|
||||
summary: Get Gotify notification settings
|
||||
@@ -3138,6 +3170,12 @@ paths:
|
||||
Updates a single slider and return the newly updated slider. Requires the `ADMIN` permission.
|
||||
tags:
|
||||
- settings
|
||||
parameters:
|
||||
- in: path
|
||||
name: sliderId
|
||||
required: true
|
||||
schema:
|
||||
type: number
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -3435,7 +3473,7 @@ paths:
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
$ref: '#/components/schemas/User'
|
||||
post:
|
||||
summary: Create new user
|
||||
description: |
|
||||
@@ -4980,7 +5018,7 @@ paths:
|
||||
- type: array
|
||||
items:
|
||||
type: number
|
||||
minimum: 1
|
||||
minimum: 0
|
||||
- type: string
|
||||
enum: [all]
|
||||
is4k:
|
||||
@@ -5086,7 +5124,7 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
type: number
|
||||
minimum: 1
|
||||
minimum: 0
|
||||
is4k:
|
||||
type: boolean
|
||||
example: false
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
"lint-staged": "13.1.2",
|
||||
"nodemon": "2.0.20",
|
||||
"postcss": "8.4.21",
|
||||
"prettier": "2.8.4",
|
||||
"prettier": "3.3.3",
|
||||
"prettier-plugin-organize-imports": "3.2.2",
|
||||
"prettier-plugin-tailwindcss": "0.2.3",
|
||||
"semantic-release": "19.0.5",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #6366F1;
|
||||
color: #6366f1;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- Inline the page's JavaScript file. -->
|
||||
<script>
|
||||
// Manual reload feature.
|
||||
document.querySelector("button").addEventListener("click", () => {
|
||||
document.querySelector('button').addEventListener('click', () => {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
|
||||
74
public/sw.js
74
public/sw.js
@@ -4,30 +4,30 @@
|
||||
// This variable is intentionally declared and unused.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const OFFLINE_VERSION = 3;
|
||||
const CACHE_NAME = "offline";
|
||||
const CACHE_NAME = 'offline';
|
||||
// Customize this with a different URL if needed.
|
||||
const OFFLINE_URL = "/offline.html";
|
||||
const OFFLINE_URL = '/offline.html';
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
// Setting {cache: 'reload'} in the new request will ensure that the
|
||||
// response isn't fulfilled from the HTTP cache; i.e., it will be from
|
||||
// the network.
|
||||
await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
|
||||
await cache.add(new Request(OFFLINE_URL, { cache: 'reload' }));
|
||||
})()
|
||||
);
|
||||
// Force the waiting service worker to become the active service worker.
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
// Enable navigation preload if it's supported.
|
||||
// See https://developers.google.com/web/updates/2017/02/navigation-preload
|
||||
if ("navigationPreload" in self.registration) {
|
||||
if ('navigationPreload' in self.registration) {
|
||||
await self.registration.navigationPreload.enable();
|
||||
}
|
||||
})()
|
||||
@@ -37,10 +37,10 @@ self.addEventListener("activate", (event) => {
|
||||
clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
self.addEventListener('fetch', (event) => {
|
||||
// We only want to call event.respondWith() if this is a navigation request
|
||||
// for an HTML page.
|
||||
if (event.request.mode === "navigate") {
|
||||
if (event.request.mode === 'navigate') {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
try {
|
||||
@@ -59,7 +59,7 @@ self.addEventListener("fetch", (event) => {
|
||||
// If fetch() returns a valid HTTP response with a response code in
|
||||
// the 4xx or 5xx range, the catch() will NOT be called.
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Fetch failed; returning offline page instead.", error);
|
||||
console.log('Fetch failed; returning offline page instead.', error);
|
||||
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cachedResponse = await cache.match(OFFLINE_URL);
|
||||
@@ -85,15 +85,13 @@ self.addEventListener('push', (event) => {
|
||||
requestId: payload.requestId,
|
||||
},
|
||||
actions: [],
|
||||
}
|
||||
};
|
||||
|
||||
if (payload.actionUrl){
|
||||
options.actions.push(
|
||||
{
|
||||
action: 'view',
|
||||
title: payload.actionUrlTitle ?? 'View',
|
||||
}
|
||||
);
|
||||
if (payload.actionUrl) {
|
||||
options.actions.push({
|
||||
action: 'view',
|
||||
title: payload.actionUrlTitle ?? 'View',
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.notificationType === 'MEDIA_PENDING') {
|
||||
@@ -109,27 +107,29 @@ self.addEventListener('push', (event) => {
|
||||
);
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(payload.subject, options)
|
||||
);
|
||||
event.waitUntil(self.registration.showNotification(payload.subject, options));
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', (event) => {
|
||||
const notificationData = event.notification.data;
|
||||
self.addEventListener(
|
||||
'notificationclick',
|
||||
(event) => {
|
||||
const notificationData = event.notification.data;
|
||||
|
||||
event.notification.close();
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'approve') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
} else if (event.action === 'decline') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
if (notificationData.actionUrl) {
|
||||
clients.openWindow(notificationData.actionUrl);
|
||||
}
|
||||
}, false);
|
||||
if (event.action === 'approve') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
} else if (event.action === 'decline') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
if (notificationData.actionUrl) {
|
||||
clients.openWindow(notificationData.actionUrl);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { PlexDevice } from '@server/interfaces/api/plexInterfaces';
|
||||
import cacheManager from '@server/lib/cache';
|
||||
import { getSettings } from '@server/lib/settings';
|
||||
import logger from '@server/logger';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import xml2js from 'xml2js';
|
||||
import ExternalAPI from './externalapi';
|
||||
|
||||
@@ -127,6 +128,11 @@ export interface PlexWatchlistItem {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface PlexWatchlistCache {
|
||||
etag: string;
|
||||
response: WatchlistResponse;
|
||||
}
|
||||
|
||||
class PlexTvAPI extends ExternalAPI {
|
||||
private authToken: string;
|
||||
|
||||
@@ -270,6 +276,11 @@ class PlexTvAPI extends ExternalAPI {
|
||||
items: PlexWatchlistItem[];
|
||||
}> {
|
||||
try {
|
||||
const watchlistCache = cacheManager.getCache('plexwatchlist');
|
||||
let cachedWatchlist = watchlistCache.data.get<PlexWatchlistCache>(
|
||||
this.authToken
|
||||
);
|
||||
|
||||
const response = await this.axios.get<WatchlistResponse>(
|
||||
'/library/sections/watchlist/all',
|
||||
{
|
||||
@@ -277,12 +288,29 @@ class PlexTvAPI extends ExternalAPI {
|
||||
'X-Plex-Container-Start': offset,
|
||||
'X-Plex-Container-Size': size,
|
||||
},
|
||||
headers: {
|
||||
'If-None-Match': cachedWatchlist?.etag,
|
||||
},
|
||||
baseURL: 'https://metadata.provider.plex.tv',
|
||||
validateStatus: (status) => status < 400, // Allow HTTP 304 to return without error
|
||||
}
|
||||
);
|
||||
|
||||
// If we don't recieve HTTP 304, the watchlist has been updated and we need to update the cache.
|
||||
if (response.status >= 200 && response.status <= 299) {
|
||||
cachedWatchlist = {
|
||||
etag: response.headers.etag,
|
||||
response: response.data,
|
||||
};
|
||||
|
||||
watchlistCache.data.set<PlexWatchlistCache>(
|
||||
this.authToken,
|
||||
cachedWatchlist
|
||||
);
|
||||
}
|
||||
|
||||
const watchlistDetails = await Promise.all(
|
||||
(response.data.MediaContainer.Metadata ?? []).map(
|
||||
(cachedWatchlist?.response.MediaContainer.Metadata ?? []).map(
|
||||
async (watchlistItem) => {
|
||||
const detailedResponse = await this.getRolling<MetadataResponse>(
|
||||
`/library/metadata/${watchlistItem.ratingKey}`,
|
||||
@@ -320,7 +348,7 @@ class PlexTvAPI extends ExternalAPI {
|
||||
return {
|
||||
offset,
|
||||
size,
|
||||
totalSize: response.data.MediaContainer.totalSize,
|
||||
totalSize: cachedWatchlist?.response.MediaContainer.totalSize ?? 0,
|
||||
items: filteredList,
|
||||
};
|
||||
} catch (e) {
|
||||
@@ -336,6 +364,24 @@ class PlexTvAPI extends ExternalAPI {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async pingToken() {
|
||||
try {
|
||||
const response = await this.axios.get('/api/v2/ping', {
|
||||
headers: {
|
||||
'X-Plex-Client-Identifier': randomUUID(),
|
||||
},
|
||||
});
|
||||
if (!response?.data?.pong) {
|
||||
throw new Error('No pong response');
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('Failed to ping token', {
|
||||
label: 'Plex Refresh Token',
|
||||
errorMessage: e.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PlexTvAPI;
|
||||
|
||||
56
server/api/pushover.ts
Normal file
56
server/api/pushover.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import ExternalAPI from './externalapi';
|
||||
|
||||
interface PushoverSoundsResponse {
|
||||
sounds: {
|
||||
[name: string]: string;
|
||||
};
|
||||
status: number;
|
||||
request: string;
|
||||
}
|
||||
|
||||
export interface PushoverSound {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const mapSounds = (sounds: {
|
||||
[name: string]: string;
|
||||
}): PushoverSound[] =>
|
||||
Object.entries(sounds).map(
|
||||
([name, description]) =>
|
||||
({
|
||||
name,
|
||||
description,
|
||||
} as PushoverSound)
|
||||
);
|
||||
|
||||
class PushoverAPI extends ExternalAPI {
|
||||
constructor() {
|
||||
super(
|
||||
'https://api.pushover.net/1',
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async getSounds(appToken: string): Promise<PushoverSound[]> {
|
||||
try {
|
||||
const data = await this.get<PushoverSoundsResponse>('/sounds.json', {
|
||||
params: {
|
||||
token: appToken,
|
||||
},
|
||||
});
|
||||
|
||||
return mapSounds(data.sounds);
|
||||
} catch (e) {
|
||||
throw new Error(`[Pushover] Failed to retrieve sounds: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PushoverAPI;
|
||||
@@ -246,9 +246,7 @@ export class MediaRequest {
|
||||
>;
|
||||
const requestedSeasons =
|
||||
requestBody.seasons === 'all'
|
||||
? tmdbMediaShow.seasons
|
||||
.map((season) => season.season_number)
|
||||
.filter((sn) => sn > 0)
|
||||
? tmdbMediaShow.seasons.map((season) => season.season_number)
|
||||
: (requestBody.seasons as number[]);
|
||||
let existingSeasons: number[] = [];
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ export class UserSettings {
|
||||
@Column({ nullable: true })
|
||||
public pushoverUserKey?: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public pushoverSound?: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public telegramChatId?: string;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ app
|
||||
cookie: {
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30,
|
||||
httpOnly: true,
|
||||
sameSite: true,
|
||||
sameSite: settings.main.csrfProtection ? 'strict' : 'lax',
|
||||
secure: 'auto',
|
||||
},
|
||||
store: new TypeormStore({
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface UserSettingsNotificationsResponse {
|
||||
pushbulletAccessToken?: string;
|
||||
pushoverApplicationToken?: string;
|
||||
pushoverUserKey?: string;
|
||||
pushoverSound?: string;
|
||||
telegramEnabled?: boolean;
|
||||
telegramBotUsername?: string;
|
||||
telegramChatId?: string;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import availabilitySync from '@server/lib/availabilitySync';
|
||||
import downloadTracker from '@server/lib/downloadtracker';
|
||||
import ImageProxy from '@server/lib/imageproxy';
|
||||
import refreshToken from '@server/lib/refreshToken';
|
||||
import { plexFullScanner, plexRecentScanner } from '@server/lib/scanners/plex';
|
||||
import { radarrScanner } from '@server/lib/scanners/radarr';
|
||||
import { sonarrScanner } from '@server/lib/scanners/sonarr';
|
||||
@@ -8,7 +9,6 @@ import type { JobId } from '@server/lib/settings';
|
||||
import { getSettings } from '@server/lib/settings';
|
||||
import watchlistSync from '@server/lib/watchlistsync';
|
||||
import logger from '@server/logger';
|
||||
import random from 'lodash/random';
|
||||
import schedule from 'node-schedule';
|
||||
|
||||
interface ScheduledJob {
|
||||
@@ -62,30 +62,20 @@ export const startJobs = (): void => {
|
||||
});
|
||||
|
||||
// Watchlist Sync
|
||||
const watchlistSyncJob: ScheduledJob = {
|
||||
scheduledJobs.push({
|
||||
id: 'plex-watchlist-sync',
|
||||
name: 'Plex Watchlist Sync',
|
||||
type: 'process',
|
||||
interval: 'fixed',
|
||||
interval: 'seconds',
|
||||
cronSchedule: jobs['plex-watchlist-sync'].schedule,
|
||||
job: schedule.scheduleJob(new Date(Date.now() + 1000 * 60 * 20), () => {
|
||||
job: schedule.scheduleJob(jobs['plex-watchlist-sync'].schedule, () => {
|
||||
logger.info('Starting scheduled job: Plex Watchlist Sync', {
|
||||
label: 'Jobs',
|
||||
});
|
||||
watchlistSync.syncWatchlist();
|
||||
}),
|
||||
};
|
||||
|
||||
// To help alleviate load on Plex's servers, we will add some fuzziness to the next schedule
|
||||
// after each run
|
||||
watchlistSyncJob.job.on('run', () => {
|
||||
watchlistSyncJob.job.schedule(
|
||||
new Date(Math.floor(Date.now() + 1000 * 60 * random(14, 24, true)))
|
||||
);
|
||||
});
|
||||
|
||||
scheduledJobs.push(watchlistSyncJob);
|
||||
|
||||
// Run full radarr scan every 24 hours
|
||||
scheduledJobs.push({
|
||||
id: 'radarr-scan',
|
||||
@@ -179,5 +169,19 @@ export const startJobs = (): void => {
|
||||
}),
|
||||
});
|
||||
|
||||
scheduledJobs.push({
|
||||
id: 'plex-refresh-token',
|
||||
name: 'Plex Refresh Token',
|
||||
type: 'process',
|
||||
interval: 'fixed',
|
||||
cronSchedule: jobs['plex-refresh-token'].schedule,
|
||||
job: schedule.scheduleJob(jobs['plex-refresh-token'].schedule, () => {
|
||||
logger.info('Starting scheduled job: Plex Refresh Token', {
|
||||
label: 'Jobs',
|
||||
});
|
||||
refreshToken.run();
|
||||
}),
|
||||
});
|
||||
|
||||
logger.info('Scheduled jobs loaded', { label: 'Jobs' });
|
||||
};
|
||||
|
||||
@@ -8,7 +8,8 @@ export type AvailableCacheIds =
|
||||
| 'imdb'
|
||||
| 'github'
|
||||
| 'plexguid'
|
||||
| 'plextv';
|
||||
| 'plextv'
|
||||
| 'plexwatchlist';
|
||||
|
||||
const DEFAULT_TTL = 300;
|
||||
const DEFAULT_CHECK_PERIOD = 120;
|
||||
@@ -68,6 +69,7 @@ class CacheManager {
|
||||
stdTtl: 86400 * 7, // 1 week cache
|
||||
checkPeriod: 60,
|
||||
}),
|
||||
plexwatchlist: new Cache('plexwatchlist', 'Plex Watchlist'),
|
||||
};
|
||||
|
||||
public getCache(id: AvailableCacheIds): Cache {
|
||||
|
||||
@@ -14,7 +14,12 @@ import {
|
||||
import type { NotificationAgent, NotificationPayload } from './agent';
|
||||
import { BaseAgent } from './agent';
|
||||
|
||||
interface PushoverPayload {
|
||||
interface PushoverImagePayload {
|
||||
attachment_base64: string;
|
||||
attachment_type: string;
|
||||
}
|
||||
|
||||
interface PushoverPayload extends PushoverImagePayload {
|
||||
token: string;
|
||||
user: string;
|
||||
title: string;
|
||||
@@ -43,10 +48,36 @@ class PushoverAgent
|
||||
return true;
|
||||
}
|
||||
|
||||
private getNotificationPayload(
|
||||
private async getImagePayload(
|
||||
imageUrl: string
|
||||
): Promise<Partial<PushoverImagePayload>> {
|
||||
try {
|
||||
const response = await axios.get(imageUrl, {
|
||||
responseType: 'arraybuffer',
|
||||
});
|
||||
const base64 = Buffer.from(response.data, 'binary').toString('base64');
|
||||
const contentType = (
|
||||
response.headers['Content-Type'] || response.headers['content-type']
|
||||
)?.toString();
|
||||
|
||||
return {
|
||||
attachment_base64: base64,
|
||||
attachment_type: contentType,
|
||||
};
|
||||
} catch (e) {
|
||||
logger.error('Error getting image payload', {
|
||||
label: 'Notifications',
|
||||
errorMessage: e.message,
|
||||
response: e.response?.data,
|
||||
});
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private async getNotificationPayload(
|
||||
type: Notification,
|
||||
payload: NotificationPayload
|
||||
): Partial<PushoverPayload> {
|
||||
): Promise<Partial<PushoverPayload>> {
|
||||
const { applicationUrl, applicationTitle } = getSettings().main;
|
||||
|
||||
const title = payload.event ?? payload.subject;
|
||||
@@ -122,6 +153,16 @@ class PushoverAgent
|
||||
? `View ${payload.issue ? 'Issue' : 'Media'} in ${applicationTitle}`
|
||||
: undefined;
|
||||
|
||||
let attachment_base64;
|
||||
let attachment_type;
|
||||
if (payload.image) {
|
||||
const imagePayload = await this.getImagePayload(payload.image);
|
||||
if (imagePayload.attachment_base64 && imagePayload.attachment_type) {
|
||||
attachment_base64 = imagePayload.attachment_base64;
|
||||
attachment_type = imagePayload.attachment_type;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
message,
|
||||
@@ -129,6 +170,8 @@ class PushoverAgent
|
||||
url_title,
|
||||
priority,
|
||||
html: 1,
|
||||
attachment_base64,
|
||||
attachment_type,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,7 +181,10 @@ class PushoverAgent
|
||||
): Promise<boolean> {
|
||||
const settings = this.getSettings();
|
||||
const endpoint = 'https://api.pushover.net/1/messages.json';
|
||||
const notificationPayload = this.getNotificationPayload(type, payload);
|
||||
const notificationPayload = await this.getNotificationPayload(
|
||||
type,
|
||||
payload
|
||||
);
|
||||
|
||||
// Send system notification
|
||||
if (
|
||||
@@ -159,6 +205,7 @@ class PushoverAgent
|
||||
...notificationPayload,
|
||||
token: settings.options.accessToken,
|
||||
user: settings.options.userToken,
|
||||
sound: settings.options.sound,
|
||||
} as PushoverPayload);
|
||||
} catch (e) {
|
||||
logger.error('Error sending Pushover notification', {
|
||||
@@ -198,6 +245,7 @@ class PushoverAgent
|
||||
...notificationPayload,
|
||||
token: payload.notifyUser.settings.pushoverApplicationToken,
|
||||
user: payload.notifyUser.settings.pushoverUserKey,
|
||||
sound: payload.notifyUser.settings.pushoverSound,
|
||||
} as PushoverPayload);
|
||||
} catch (e) {
|
||||
logger.error('Error sending Pushover notification', {
|
||||
|
||||
37
server/lib/refreshToken.ts
Normal file
37
server/lib/refreshToken.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import PlexTvAPI from '@server/api/plextv';
|
||||
import { getRepository } from '@server/datasource';
|
||||
import { User } from '@server/entity/User';
|
||||
import logger from '@server/logger';
|
||||
|
||||
class RefreshToken {
|
||||
public async run() {
|
||||
const userRepository = getRepository(User);
|
||||
|
||||
const users = await userRepository
|
||||
.createQueryBuilder('user')
|
||||
.addSelect('user.plexToken')
|
||||
.where("user.plexToken != ''")
|
||||
.getMany();
|
||||
|
||||
for (const user of users) {
|
||||
await this.refreshUserToken(user);
|
||||
}
|
||||
}
|
||||
|
||||
private async refreshUserToken(user: User) {
|
||||
if (!user.plexToken) {
|
||||
logger.warn('Skipping user refresh token for user without plex token', {
|
||||
label: 'Plex Refresh Token',
|
||||
user: user.displayName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const plexTvApi = new PlexTvAPI(user.plexToken);
|
||||
plexTvApi.pingToken();
|
||||
}
|
||||
}
|
||||
|
||||
const refreshToken = new RefreshToken();
|
||||
|
||||
export default refreshToken;
|
||||
@@ -278,9 +278,7 @@ class PlexScanner
|
||||
const seasons = tvShow.seasons;
|
||||
const processableSeasons: ProcessableSeason[] = [];
|
||||
|
||||
const filteredSeasons = seasons.filter((sn) => sn.season_number !== 0);
|
||||
|
||||
for (const season of filteredSeasons) {
|
||||
for (const season of seasons) {
|
||||
const matchedPlexSeason = metadata.Children?.Metadata.find(
|
||||
(md) => Number(md.index) === season.season_number
|
||||
);
|
||||
|
||||
@@ -103,10 +103,8 @@ class SonarrScanner
|
||||
|
||||
const tmdbId = tvShow.id;
|
||||
|
||||
const filteredSeasons = sonarrSeries.seasons.filter(
|
||||
(sn) =>
|
||||
sn.seasonNumber !== 0 &&
|
||||
tvShow.seasons.find((s) => s.season_number === sn.seasonNumber)
|
||||
const filteredSeasons = sonarrSeries.seasons.filter((sn) =>
|
||||
tvShow.seasons.find((s) => s.season_number === sn.seasonNumber)
|
||||
);
|
||||
|
||||
for (const season of filteredSeasons) {
|
||||
|
||||
@@ -192,6 +192,7 @@ export interface NotificationAgentPushover extends NotificationAgentConfig {
|
||||
options: {
|
||||
accessToken: string;
|
||||
userToken: string;
|
||||
sound: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -247,6 +248,7 @@ export type JobId =
|
||||
| 'plex-recently-added-scan'
|
||||
| 'plex-full-scan'
|
||||
| 'plex-watchlist-sync'
|
||||
| 'plex-refresh-token'
|
||||
| 'radarr-scan'
|
||||
| 'sonarr-scan'
|
||||
| 'download-sync'
|
||||
@@ -372,6 +374,7 @@ class Settings {
|
||||
options: {
|
||||
accessToken: '',
|
||||
userToken: '',
|
||||
sound: '',
|
||||
},
|
||||
},
|
||||
webhook: {
|
||||
@@ -405,7 +408,10 @@ class Settings {
|
||||
schedule: '0 0 3 * * *',
|
||||
},
|
||||
'plex-watchlist-sync': {
|
||||
schedule: '0 */10 * * * *',
|
||||
schedule: '0 */3 * * * *',
|
||||
},
|
||||
'plex-refresh-token': {
|
||||
schedule: '0 0 5 * * *',
|
||||
},
|
||||
'radarr-scan': {
|
||||
schedule: '0 0 4 * * *',
|
||||
|
||||
@@ -62,7 +62,7 @@ class WatchlistSync {
|
||||
|
||||
const plexTvApi = new PlexTvAPI(user.plexToken);
|
||||
|
||||
const response = await plexTvApi.getWatchlist({ size: 200 });
|
||||
const response = await plexTvApi.getWatchlist({ size: 20 });
|
||||
|
||||
const mediaItems = await Media.getRelatedMedia(
|
||||
response.items.map((i) => i.tmdbId)
|
||||
@@ -79,82 +79,80 @@ class WatchlistSync {
|
||||
)
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
unavailableItems.map(async (mediaItem) => {
|
||||
try {
|
||||
logger.info("Creating media request from user's Plex Watchlist", {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
});
|
||||
for (const mediaItem of unavailableItems) {
|
||||
try {
|
||||
logger.info("Creating media request from user's Plex Watchlist", {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
});
|
||||
|
||||
if (mediaItem.type === 'show' && !mediaItem.tvdbId) {
|
||||
throw new Error('Missing TVDB ID from Plex Metadata');
|
||||
}
|
||||
|
||||
// Check if they have auto-request permissons and watchlist sync
|
||||
// enabled for the media type
|
||||
if (
|
||||
((!user.hasPermission(
|
||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],
|
||||
{ type: 'or' }
|
||||
) ||
|
||||
!user.settings?.watchlistSyncMovies) &&
|
||||
mediaItem.type === 'movie') ||
|
||||
((!user.hasPermission(
|
||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],
|
||||
{ type: 'or' }
|
||||
) ||
|
||||
!user.settings?.watchlistSyncTv) &&
|
||||
mediaItem.type === 'show')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await MediaRequest.request(
|
||||
{
|
||||
mediaId: mediaItem.tmdbId,
|
||||
mediaType:
|
||||
mediaItem.type === 'show' ? MediaType.TV : MediaType.MOVIE,
|
||||
seasons: mediaItem.type === 'show' ? 'all' : undefined,
|
||||
tvdbId: mediaItem.tvdbId,
|
||||
is4k: false,
|
||||
},
|
||||
user,
|
||||
{ isAutoRequest: true }
|
||||
);
|
||||
} catch (e) {
|
||||
if (!(e instanceof Error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.constructor) {
|
||||
// During watchlist sync, these errors aren't necessarily
|
||||
// a problem with Overseerr. Since we are auto syncing these constantly, it's
|
||||
// possible they are unexpectedly at their quota limit, for example. So we'll
|
||||
// instead log these as debug messages.
|
||||
case RequestPermissionError:
|
||||
case DuplicateMediaRequestError:
|
||||
case QuotaRestrictedError:
|
||||
case NoSeasonsAvailableError:
|
||||
logger.debug('Failed to create media request from watchlist', {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
errorMessage: e.message,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
logger.error('Failed to create media request from watchlist', {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
errorMessage: e.message,
|
||||
});
|
||||
}
|
||||
if (mediaItem.type === 'show' && !mediaItem.tvdbId) {
|
||||
throw new Error('Missing TVDB ID from Plex Metadata');
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Check if they have auto-request permissons and watchlist sync
|
||||
// enabled for the media type
|
||||
if (
|
||||
((!user.hasPermission(
|
||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],
|
||||
{ type: 'or' }
|
||||
) ||
|
||||
!user.settings?.watchlistSyncMovies) &&
|
||||
mediaItem.type === 'movie') ||
|
||||
((!user.hasPermission(
|
||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],
|
||||
{ type: 'or' }
|
||||
) ||
|
||||
!user.settings?.watchlistSyncTv) &&
|
||||
mediaItem.type === 'show')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await MediaRequest.request(
|
||||
{
|
||||
mediaId: mediaItem.tmdbId,
|
||||
mediaType:
|
||||
mediaItem.type === 'show' ? MediaType.TV : MediaType.MOVIE,
|
||||
seasons: mediaItem.type === 'show' ? 'all' : undefined,
|
||||
tvdbId: mediaItem.tvdbId,
|
||||
is4k: false,
|
||||
},
|
||||
user,
|
||||
{ isAutoRequest: true }
|
||||
);
|
||||
} catch (e) {
|
||||
if (!(e instanceof Error)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (e.constructor) {
|
||||
// During watchlist sync, these errors aren't necessarily
|
||||
// a problem with Overseerr. Since we are auto syncing these constantly, it's
|
||||
// possible they are unexpectedly at their quota limit, for example. So we'll
|
||||
// instead log these as debug messages.
|
||||
case RequestPermissionError:
|
||||
case DuplicateMediaRequestError:
|
||||
case QuotaRestrictedError:
|
||||
case NoSeasonsAvailableError:
|
||||
logger.debug('Failed to create media request from watchlist', {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
errorMessage: e.message,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
logger.error('Failed to create media request from watchlist', {
|
||||
label: 'Watchlist Sync',
|
||||
userId: user.id,
|
||||
mediaTitle: mediaItem.title,
|
||||
errorMessage: e.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
31
server/migration/1697393491630-AddUserPushoverSound.ts
Normal file
31
server/migration/1697393491630-AddUserPushoverSound.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddUserPushoverSound1697393491630 implements MigrationInterface {
|
||||
name = 'AddUserPushoverSound1697393491630';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`INSERT INTO "temporary_user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv" FROM "user_settings"`
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "user_settings"`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"`
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`INSERT INTO "user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv" FROM "temporary_user_settings"`
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "temporary_user_settings"`);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ collectionRoutes.get<{ id: string }>('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const collection = await tmdb.getCollection({
|
||||
collectionId: Number(req.params.id),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
|
||||
@@ -164,7 +164,7 @@ discoverRoutes.get<{ language: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverMovies({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
originalLanguage: req.params.language,
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@ discoverRoutes.get<{ genreId: string }>(
|
||||
|
||||
try {
|
||||
const genres = await tmdb.getMovieGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const genre = genres.find(
|
||||
@@ -221,7 +221,7 @@ discoverRoutes.get<{ genreId: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverMovies({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
genre: req.params.genreId as string,
|
||||
});
|
||||
|
||||
@@ -268,7 +268,7 @@ discoverRoutes.get<{ studioId: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverMovies({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
studio: req.params.studioId as string,
|
||||
});
|
||||
|
||||
@@ -317,7 +317,7 @@ discoverRoutes.get('/movies/upcoming', async (req, res, next) => {
|
||||
try {
|
||||
const data = await tmdb.getDiscoverMovies({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
primaryReleaseDateGte: date,
|
||||
});
|
||||
|
||||
@@ -440,7 +440,7 @@ discoverRoutes.get<{ language: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverTv({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
originalLanguage: req.params.language,
|
||||
});
|
||||
|
||||
@@ -484,7 +484,7 @@ discoverRoutes.get<{ genreId: string }>(
|
||||
|
||||
try {
|
||||
const genres = await tmdb.getTvGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const genre = genres.find(
|
||||
@@ -497,7 +497,7 @@ discoverRoutes.get<{ genreId: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverTv({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
genre: req.params.genreId,
|
||||
});
|
||||
|
||||
@@ -544,7 +544,7 @@ discoverRoutes.get<{ networkId: string }>(
|
||||
|
||||
const data = await tmdb.getDiscoverTv({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
network: Number(req.params.networkId),
|
||||
});
|
||||
|
||||
@@ -593,7 +593,7 @@ discoverRoutes.get('/tv/upcoming', async (req, res, next) => {
|
||||
try {
|
||||
const data = await tmdb.getDiscoverTv({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
firstAirDateGte: date,
|
||||
});
|
||||
|
||||
@@ -632,7 +632,7 @@ discoverRoutes.get('/trending', async (req, res, next) => {
|
||||
try {
|
||||
const data = await tmdb.getAllTrending({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
@@ -686,7 +686,7 @@ discoverRoutes.get<{ keywordId: string }>(
|
||||
const data = await tmdb.getMoviesByKeyword({
|
||||
keywordId: Number(req.params.keywordId),
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
@@ -730,7 +730,7 @@ discoverRoutes.get<{ language: string }, GenreSliderItem[]>(
|
||||
const mappedGenres: GenreSliderItem[] = [];
|
||||
|
||||
const genres = await tmdb.getMovieGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
@@ -774,7 +774,7 @@ discoverRoutes.get<{ language: string }, GenreSliderItem[]>(
|
||||
const mappedGenres: GenreSliderItem[] = [];
|
||||
|
||||
const genres = await tmdb.getTvGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import GithubAPI from '@server/api/github';
|
||||
import PushoverAPI from '@server/api/pushover';
|
||||
import TheMovieDb from '@server/api/themoviedb';
|
||||
import type {
|
||||
TmdbMovieResult,
|
||||
@@ -112,6 +113,31 @@ router.get('/settings/discover', isAuthenticated(), async (_req, res) => {
|
||||
|
||||
return res.json(sliders);
|
||||
});
|
||||
router.get(
|
||||
'/settings/notifications/pushover/sounds',
|
||||
isAuthenticated(),
|
||||
async (req, res, next) => {
|
||||
const pushoverApi = new PushoverAPI();
|
||||
|
||||
try {
|
||||
if (!req.query.token) {
|
||||
throw new Error('Pushover application token missing from request');
|
||||
}
|
||||
|
||||
const sounds = await pushoverApi.getSounds(req.query.token as string);
|
||||
res.status(200).json(sounds);
|
||||
} catch (e) {
|
||||
logger.debug('Something went wrong retrieving Pushover sounds', {
|
||||
label: 'API',
|
||||
errorMessage: e.message,
|
||||
});
|
||||
return next({
|
||||
status: 500,
|
||||
message: 'Unable to retrieve Pushover sounds.',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
router.use('/settings', isAuthenticated(Permission.ADMIN), settingsRoutes);
|
||||
router.use('/search', isAuthenticated(), searchRoutes);
|
||||
router.use('/discover', isAuthenticated(), discoverRoutes);
|
||||
@@ -209,7 +235,7 @@ router.get('/genres/movie', isAuthenticated(), async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const genres = await tmdb.getMovieGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
return res.status(200).json(genres);
|
||||
@@ -230,7 +256,7 @@ router.get('/genres/tv', isAuthenticated(), async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const genres = await tmdb.getTvGenres({
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
return res.status(200).json(genres);
|
||||
|
||||
@@ -17,7 +17,7 @@ movieRoutes.get('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const tmdbMovie = await tmdb.getMovie({
|
||||
movieId: Number(req.params.id),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getMedia(tmdbMovie.id, MediaType.MOVIE);
|
||||
@@ -43,7 +43,7 @@ movieRoutes.get('/:id/recommendations', async (req, res, next) => {
|
||||
const results = await tmdb.getMovieRecommendations({
|
||||
movieId: Number(req.params.id),
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
@@ -84,7 +84,7 @@ movieRoutes.get('/:id/similar', async (req, res, next) => {
|
||||
const results = await tmdb.getMovieSimilar({
|
||||
movieId: Number(req.params.id),
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
|
||||
@@ -16,7 +16,7 @@ personRoutes.get('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const person = await tmdb.getPerson({
|
||||
personId: Number(req.params.id),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
return res.status(200).json(mapPersonDetails(person));
|
||||
} catch (e) {
|
||||
@@ -38,7 +38,7 @@ personRoutes.get('/:id/combined_credits', async (req, res, next) => {
|
||||
try {
|
||||
const combinedCredits = await tmdb.getPersonCombinedCredits({
|
||||
personId: Number(req.params.id),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const castMedia = await Media.getRelatedMedia(
|
||||
|
||||
@@ -20,7 +20,7 @@ searchRoutes.get('/', async (req, res, next) => {
|
||||
.match(searchProvider.pattern) as RegExpMatchArray;
|
||||
results = await searchProvider.search({
|
||||
id,
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
query: queryString,
|
||||
});
|
||||
} else {
|
||||
@@ -29,7 +29,7 @@ searchRoutes.get('/', async (req, res, next) => {
|
||||
results = await tmdb.searchMulti({
|
||||
query: queryString,
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ tvRoutes.get('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const tv = await tmdb.getTvShow({
|
||||
tvId: Number(req.params.id),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getMedia(tv.id, MediaType.TV);
|
||||
@@ -40,7 +40,7 @@ tvRoutes.get('/:id/season/:seasonNumber', async (req, res, next) => {
|
||||
const season = await tmdb.getTvSeason({
|
||||
tvId: Number(req.params.id),
|
||||
seasonNumber: Number(req.params.seasonNumber),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
return res.status(200).json(mapSeasonWithEpisodes(season));
|
||||
@@ -65,7 +65,7 @@ tvRoutes.get('/:id/recommendations', async (req, res, next) => {
|
||||
const results = await tmdb.getTvRecommendations({
|
||||
tvId: Number(req.params.id),
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
@@ -105,7 +105,7 @@ tvRoutes.get('/:id/similar', async (req, res, next) => {
|
||||
const results = await tmdb.getTvSimilar({
|
||||
tvId: Number(req.params.id),
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
language: (req.query.language as string) ?? req.locale,
|
||||
});
|
||||
|
||||
const media = await Media.getRelatedMedia(
|
||||
|
||||
@@ -262,7 +262,7 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
emailEnabled: settings?.email.enabled,
|
||||
emailEnabled: settings.email.enabled,
|
||||
pgpKey: user.settings?.pgpKey,
|
||||
discordEnabled:
|
||||
settings?.discord.enabled && settings.discord.options.enableMentions,
|
||||
@@ -274,11 +274,12 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
pushbulletAccessToken: user.settings?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: user.settings?.pushoverApplicationToken,
|
||||
pushoverUserKey: user.settings?.pushoverUserKey,
|
||||
telegramEnabled: settings?.telegram.enabled,
|
||||
telegramBotUsername: settings?.telegram.options.botUsername,
|
||||
pushoverSound: user.settings?.pushoverSound,
|
||||
telegramEnabled: settings.telegram.enabled,
|
||||
telegramBotUsername: settings.telegram.options.botUsername,
|
||||
telegramChatId: user.settings?.telegramChatId,
|
||||
telegramSendSilently: user?.settings?.telegramSendSilently,
|
||||
webPushEnabled: settings?.webpush.enabled,
|
||||
telegramSendSilently: user.settings?.telegramSendSilently,
|
||||
webPushEnabled: settings.webpush.enabled,
|
||||
notificationTypes: user.settings?.notificationTypes ?? {},
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -329,6 +330,7 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
user.settings.pushoverApplicationToken =
|
||||
req.body.pushoverApplicationToken;
|
||||
user.settings.pushoverUserKey = req.body.pushoverUserKey;
|
||||
user.settings.pushoverSound = req.body.pushoverSound;
|
||||
user.settings.telegramChatId = req.body.telegramChatId;
|
||||
user.settings.telegramSendSilently = req.body.telegramSendSilently;
|
||||
user.settings.notificationTypes = Object.assign(
|
||||
@@ -341,13 +343,14 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
userRepository.save(user);
|
||||
|
||||
return res.status(200).json({
|
||||
pgpKey: user.settings?.pgpKey,
|
||||
discordId: user.settings?.discordId,
|
||||
pushbulletAccessToken: user.settings?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: user.settings?.pushoverApplicationToken,
|
||||
pushoverUserKey: user.settings?.pushoverUserKey,
|
||||
telegramChatId: user.settings?.telegramChatId,
|
||||
telegramSendSilently: user?.settings?.telegramSendSilently,
|
||||
pgpKey: user.settings.pgpKey,
|
||||
discordId: user.settings.discordId,
|
||||
pushbulletAccessToken: user.settings.pushbulletAccessToken,
|
||||
pushoverApplicationToken: user.settings.pushoverApplicationToken,
|
||||
pushoverUserKey: user.settings.pushoverUserKey,
|
||||
pushoverSound: user.settings.pushoverSound,
|
||||
telegramChatId: user.settings.telegramChatId,
|
||||
telegramSendSilently: user.settings.telegramSendSilently,
|
||||
notificationTypes: user.settings.notificationTypes,
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -16,9 +16,9 @@ architectures:
|
||||
parts:
|
||||
overseerr:
|
||||
plugin: nodejs
|
||||
nodejs-version: '16.17.0'
|
||||
nodejs-version: '18.18.2'
|
||||
nodejs-package-manager: 'yarn'
|
||||
nodejs-yarn-version: v1.22.17
|
||||
nodejs-yarn-version: v1.22.19
|
||||
build-packages:
|
||||
- git
|
||||
- on arm64:
|
||||
|
||||
@@ -73,6 +73,12 @@ const studios: Studio[] = [
|
||||
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/2Tc1P3Ac8M479naPp1kYT3izLS5.png',
|
||||
url: '/discover/movies/studio/9993',
|
||||
},
|
||||
{
|
||||
name: 'A24',
|
||||
image:
|
||||
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1ZXsGaFPgrgS6ZZGS37AqD5uU12.png',
|
||||
url: '/discover/movies/studio/41077',
|
||||
},
|
||||
];
|
||||
|
||||
const StudioSlider = () => {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
const PullToRefresh = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const [pullStartPoint, setPullStartPoint] = useState(0);
|
||||
const [pullChange, setPullChange] = useState(0);
|
||||
const refreshDiv = useRef<HTMLDivElement>(null);
|
||||
@@ -19,6 +18,7 @@ const PullToRefresh = () => {
|
||||
// Reload function that is called when reload threshold has been hit
|
||||
// Add loading class to determine when to add spin animation
|
||||
const forceReload = () => {
|
||||
setPullStartPoint(0);
|
||||
refreshDiv.current?.classList.add('loading');
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
@@ -32,6 +32,8 @@ const PullToRefresh = () => {
|
||||
const pullStart = (e: TouchEvent) => {
|
||||
setPullStartPoint(e.targetTouches[0].screenY);
|
||||
|
||||
const html = document.querySelector('html');
|
||||
|
||||
if (window.scrollY === 0 && window.scrollX === 0) {
|
||||
refreshDiv.current?.classList.add('block');
|
||||
refreshDiv.current?.classList.remove('hidden');
|
||||
@@ -41,6 +43,7 @@ const PullToRefresh = () => {
|
||||
html.style.overscrollBehaviorY = 'none';
|
||||
}
|
||||
} else {
|
||||
setPullStartPoint(0);
|
||||
refreshDiv.current?.classList.remove('block');
|
||||
refreshDiv.current?.classList.add('hidden');
|
||||
}
|
||||
@@ -49,7 +52,6 @@ const PullToRefresh = () => {
|
||||
// Tracks how far we have pulled down the refresh icon
|
||||
const pullDown = async (e: TouchEvent) => {
|
||||
const screenY = e.targetTouches[0].screenY;
|
||||
|
||||
const pullLength =
|
||||
pullStartPoint < screenY ? Math.abs(screenY - pullStartPoint) : 0;
|
||||
|
||||
@@ -59,12 +61,11 @@ const PullToRefresh = () => {
|
||||
// Will reload the page if we are past the threshold
|
||||
// Otherwise, we reset the pull
|
||||
const pullFinish = () => {
|
||||
setPullStartPoint(0);
|
||||
|
||||
if (pullDownReloadThreshold) {
|
||||
if (pullDownReloadThreshold && pullStartPoint !== 0) {
|
||||
forceReload();
|
||||
} else {
|
||||
setPullChange(0);
|
||||
setTimeout(() => setPullStartPoint(0), 200);
|
||||
}
|
||||
|
||||
document.body.style.touchAction = 'auto';
|
||||
@@ -83,7 +84,21 @@ const PullToRefresh = () => {
|
||||
window.removeEventListener('touchmove', pullDown);
|
||||
window.removeEventListener('touchend', pullFinish);
|
||||
};
|
||||
}, [pullDownInitThreshold, pullDownReloadThreshold, pullStartPoint, router]);
|
||||
}, [
|
||||
pullDownInitThreshold,
|
||||
pullDownReloadThreshold,
|
||||
pullStartPoint,
|
||||
refreshDiv,
|
||||
router,
|
||||
setPullStartPoint,
|
||||
]);
|
||||
|
||||
if (
|
||||
pullStartPoint === 0 &&
|
||||
!refreshDiv.current?.classList.contains('loading')
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -102,7 +117,7 @@ const PullToRefresh = () => {
|
||||
<div
|
||||
className={`${
|
||||
refreshDiv.current?.classList.contains('loading') && 'animate-spin'
|
||||
} relative -top-24 h-9 w-9 rounded-full border-4 border-gray-800 bg-gray-800 shadow-md shadow-black ring-1 ring-gray-700`}
|
||||
} relative -top-28 h-9 w-9 rounded-full border-4 border-gray-800 bg-gray-800 shadow-md shadow-black ring-1 ring-gray-700`}
|
||||
style={{ animationDirection: 'reverse' }}
|
||||
>
|
||||
<ArrowPathIcon
|
||||
|
||||
@@ -500,7 +500,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative z-10 flex h-14 items-center justify-between p-4 text-gray-200 transition duration-300 group-hover:text-white">
|
||||
<div className="relative z-10 flex h-full items-center justify-between p-4 text-gray-200 transition duration-300 group-hover:text-white">
|
||||
<div>{data.collection.name}</div>
|
||||
<Button buttonSize="sm">
|
||||
{intl.formatMessage(globalMessages.view)}
|
||||
|
||||
@@ -76,8 +76,12 @@ const RegionSelector = ({
|
||||
}, [value, regions, allRegion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onChange && regions && selectedRegion) {
|
||||
onChange(name, selectedRegion.iso_3166_1);
|
||||
if (onChange && regions) {
|
||||
if (selectedRegion) {
|
||||
onChange(name, selectedRegion.iso_3166_1);
|
||||
} else {
|
||||
onChange(name, '');
|
||||
}
|
||||
}
|
||||
}, [onChange, selectedRegion, name, regions]);
|
||||
|
||||
|
||||
@@ -210,13 +210,24 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
<Tooltip content={intl.formatMessage(messages.requestdate)}>
|
||||
<CalendarIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
||||
</Tooltip>
|
||||
<span>
|
||||
{intl.formatDate(request.createdAt, {
|
||||
<Tooltip
|
||||
content={intl.formatDate(request.createdAt, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric',
|
||||
})}
|
||||
</span>
|
||||
>
|
||||
<span>
|
||||
{intl.formatDate(request.createdAt, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
{(request.seasons ?? []).length > 0 && (
|
||||
@@ -232,7 +243,11 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
key={`season-${season.id}`}
|
||||
className="mb-1 mr-2 inline-block"
|
||||
>
|
||||
<Badge>{season.seasonNumber}</Badge>
|
||||
<Badge>
|
||||
{season.seasonNumber === 0
|
||||
? intl.formatMessage(globalMessages.specials)
|
||||
: season.seasonNumber}
|
||||
</Badge>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -381,8 +381,7 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
<span className="mr-2 font-bold ">
|
||||
{intl.formatMessage(messages.seasons, {
|
||||
seasonCount:
|
||||
title.seasons.filter((season) => season.seasonNumber !== 0)
|
||||
.length === request.seasons.length
|
||||
title.seasons.length === request.seasons.length
|
||||
? 0
|
||||
: request.seasons.length,
|
||||
})}
|
||||
@@ -390,7 +389,11 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
<div className="hide-scrollbar overflow-x-scroll">
|
||||
{request.seasons.map((season) => (
|
||||
<span key={`season-${season.id}`} className="mr-2">
|
||||
<Badge>{season.seasonNumber}</Badge>
|
||||
<Badge>
|
||||
{season.seasonNumber === 0
|
||||
? intl.formatMessage(globalMessages.specials)
|
||||
: season.seasonNumber}
|
||||
</Badge>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -440,9 +440,7 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
<span className="card-field-name">
|
||||
{intl.formatMessage(messages.seasons, {
|
||||
seasonCount:
|
||||
title.seasons.filter(
|
||||
(season) => season.seasonNumber !== 0
|
||||
).length === request.seasons.length
|
||||
title.seasons.length === request.seasons.length
|
||||
? 0
|
||||
: request.seasons.length,
|
||||
})}
|
||||
@@ -450,7 +448,11 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
<div className="hide-scrollbar flex flex-nowrap overflow-x-scroll">
|
||||
{request.seasons.map((season) => (
|
||||
<span key={`season-${season.id}`} className="mr-2">
|
||||
<Badge>{season.seasonNumber}</Badge>
|
||||
<Badge>
|
||||
{season.seasonNumber === 0
|
||||
? intl.formatMessage(globalMessages.specials)
|
||||
: season.seasonNumber}
|
||||
</Badge>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,6 @@ const messages = defineMessages({
|
||||
season: 'Season',
|
||||
numberofepisodes: '# of Episodes',
|
||||
seasonnumber: 'Season {number}',
|
||||
extras: 'Extras',
|
||||
errorediting: 'Something went wrong while editing the request.',
|
||||
requestedited: 'Request for <strong>{title}</strong> edited successfully!',
|
||||
requestApproved: 'Request for <strong>{title}</strong> approved!',
|
||||
@@ -232,9 +231,7 @@ const TvRequestModal = ({
|
||||
|
||||
const getAllSeasons = (): number[] => {
|
||||
return (data?.seasons ?? [])
|
||||
.filter(
|
||||
(season) => season.seasonNumber !== 0 && season.episodeCount !== 0
|
||||
)
|
||||
.filter((season) => season.episodeCount !== 0)
|
||||
.map((season) => season.seasonNumber);
|
||||
};
|
||||
|
||||
@@ -557,10 +554,7 @@ const TvRequestModal = ({
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-700">
|
||||
{data?.seasons
|
||||
.filter(
|
||||
(season) =>
|
||||
season.seasonNumber !== 0 && season.episodeCount !== 0
|
||||
)
|
||||
.filter((season) => season.episodeCount !== 0)
|
||||
.map((season) => {
|
||||
const seasonRequest = getSeasonRequest(
|
||||
season.seasonNumber
|
||||
@@ -637,7 +631,7 @@ const TvRequestModal = ({
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-1 py-4 text-sm font-medium leading-5 text-gray-100 md:px-6">
|
||||
{season.seasonNumber === 0
|
||||
? intl.formatMessage(messages.extras)
|
||||
? intl.formatMessage(globalMessages.specials)
|
||||
: intl.formatMessage(messages.seasonnumber, {
|
||||
number: season.seasonNumber,
|
||||
})}
|
||||
|
||||
@@ -3,6 +3,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||
import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import type { PushoverSound } from '@server/api/pushover';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
@@ -19,6 +20,8 @@ const messages = defineMessages({
|
||||
userToken: 'User or Group Key',
|
||||
userTokenTip:
|
||||
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
||||
sound: 'Notification Sound',
|
||||
deviceDefault: 'Device Default',
|
||||
validationAccessTokenRequired: 'You must provide a valid application token',
|
||||
validationUserTokenRequired: 'You must provide a valid user or group key',
|
||||
pushoversettingssaved: 'Pushover notification settings saved successfully!',
|
||||
@@ -38,6 +41,11 @@ const NotificationsPushover = () => {
|
||||
error,
|
||||
mutate: revalidate,
|
||||
} = useSWR('/api/v1/settings/notifications/pushover');
|
||||
const { data: soundsData } = useSWR<PushoverSound[]>(
|
||||
data?.options.accessToken
|
||||
? `/api/v1/settings/notifications/pushover/sounds?token=${data.options.accessToken}`
|
||||
: null
|
||||
);
|
||||
|
||||
const NotificationsPushoverSchema = Yup.object().shape({
|
||||
accessToken: Yup.string()
|
||||
@@ -77,6 +85,7 @@ const NotificationsPushover = () => {
|
||||
types: data?.types,
|
||||
accessToken: data?.options.accessToken,
|
||||
userToken: data?.options.userToken,
|
||||
sound: data?.options.sound,
|
||||
}}
|
||||
validationSchema={NotificationsPushoverSchema}
|
||||
onSubmit={async (values) => {
|
||||
@@ -132,6 +141,7 @@ const NotificationsPushover = () => {
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
sound: values.sound,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -226,6 +236,30 @@ const NotificationsPushover = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="sound" className="text-label">
|
||||
{intl.formatMessage(messages.sound)}
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<div className="form-input-field">
|
||||
<Field
|
||||
as="select"
|
||||
id="sound"
|
||||
name="sound"
|
||||
disabled={!soundsData?.length}
|
||||
>
|
||||
<option value="">
|
||||
{intl.formatMessage(messages.deviceDefault)}
|
||||
</option>
|
||||
{soundsData?.map((sound, index) => (
|
||||
<option key={`sound-${index}`} value={sound.name}>
|
||||
{sound.description}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NotificationTypeSelector
|
||||
currentTypes={values.enabled ? values.types : 0}
|
||||
onUpdate={(newTypes) => {
|
||||
|
||||
@@ -53,6 +53,7 @@ const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
|
||||
'plex-recently-added-scan': 'Plex Recently Added Scan',
|
||||
'plex-full-scan': 'Plex Full Library Scan',
|
||||
'plex-watchlist-sync': 'Plex Watchlist Sync',
|
||||
'plex-refresh-token': 'Plex Refresh Token',
|
||||
'availability-sync': 'Media Availability Sync',
|
||||
'radarr-scan': 'Radarr Scan',
|
||||
'sonarr-scan': 'Sonarr Scan',
|
||||
|
||||
@@ -200,6 +200,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Does NOT include "Specials"
|
||||
const seasonCount = data.seasons.filter(
|
||||
(season) => season.seasonNumber !== 0 && season.episodeCount !== 0
|
||||
).length;
|
||||
@@ -257,9 +258,17 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
return [...requestedSeasons, ...availableSeasons];
|
||||
};
|
||||
|
||||
const isComplete = seasonCount <= getAllRequestedSeasons(false).length;
|
||||
const showHasSpecials = data.seasons.some(
|
||||
(season) => season.seasonNumber === 0
|
||||
);
|
||||
|
||||
const is4kComplete = seasonCount <= getAllRequestedSeasons(true).length;
|
||||
const isComplete =
|
||||
(showHasSpecials ? seasonCount + 1 : seasonCount) <=
|
||||
getAllRequestedSeasons(false).length;
|
||||
|
||||
const is4kComplete =
|
||||
(showHasSpecials ? seasonCount + 1 : seasonCount) <=
|
||||
getAllRequestedSeasons(true).length;
|
||||
|
||||
const streamingProviders =
|
||||
data?.watchProviders?.find((provider) => provider.iso_3166_1 === region)
|
||||
@@ -522,7 +531,6 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
{data.seasons
|
||||
.slice()
|
||||
.reverse()
|
||||
.filter((season) => season.seasonNumber !== 0)
|
||||
.map((season) => {
|
||||
const show4k =
|
||||
settings.currentSettings.series4kEnabled &&
|
||||
@@ -576,9 +584,11 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
||||
>
|
||||
<div className="flex flex-1 items-center space-x-2 text-lg">
|
||||
<span>
|
||||
{intl.formatMessage(messages.seasonnumber, {
|
||||
seasonNumber: season.seasonNumber,
|
||||
})}
|
||||
{season.seasonNumber === 0
|
||||
? intl.formatMessage(globalMessages.specials)
|
||||
: intl.formatMessage(messages.seasonnumber, {
|
||||
seasonNumber: season.seasonNumber,
|
||||
})}
|
||||
</span>
|
||||
<Badge badgeType="dark">
|
||||
{intl.formatMessage(messages.episodeCount, {
|
||||
|
||||
@@ -4,6 +4,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import type { PushoverSound } from '@server/api/pushover';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
@@ -22,6 +23,8 @@ const messages = defineMessages({
|
||||
pushoverUserKey: 'User or Group Key',
|
||||
pushoverUserKeyTip:
|
||||
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
||||
sound: 'Notification Sound',
|
||||
deviceDefault: 'Device Default',
|
||||
validationPushoverApplicationToken:
|
||||
'You must provide a valid application token',
|
||||
validationPushoverUserKey: 'You must provide a valid user or group key',
|
||||
@@ -40,6 +43,11 @@ const UserPushoverSettings = () => {
|
||||
} = useSWR<UserSettingsNotificationsResponse>(
|
||||
user ? `/api/v1/user/${user?.id}/settings/notifications` : null
|
||||
);
|
||||
const { data: soundsData } = useSWR<PushoverSound[]>(
|
||||
data?.pushoverApplicationToken
|
||||
? `/api/v1/settings/notifications/pushover/sounds?token=${data.pushoverApplicationToken}`
|
||||
: null
|
||||
);
|
||||
|
||||
const UserNotificationsPushoverSchema = Yup.object().shape({
|
||||
pushoverApplicationToken: Yup.string()
|
||||
@@ -191,6 +199,30 @@ const UserPushoverSettings = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="sound" className="text-label">
|
||||
{intl.formatMessage(messages.sound)}
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<div className="form-input-field">
|
||||
<Field
|
||||
as="select"
|
||||
id="sound"
|
||||
name="sound"
|
||||
disabled={!soundsData?.length}
|
||||
>
|
||||
<option value="">
|
||||
{intl.formatMessage(messages.deviceDefault)}
|
||||
</option>
|
||||
{soundsData?.map((sound, index) => (
|
||||
<option key={`sound-${index}`} value={sound.name}>
|
||||
{sound.description}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NotificationTypeSelector
|
||||
user={user}
|
||||
currentTypes={values.types}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
|
||||
export type AvailableLocale =
|
||||
| 'ar'
|
||||
| 'bg'
|
||||
| 'ca'
|
||||
| 'cs'
|
||||
| 'da'
|
||||
@@ -9,8 +10,11 @@ export type AvailableLocale =
|
||||
| 'en'
|
||||
| 'el'
|
||||
| 'es'
|
||||
| 'fi'
|
||||
| 'fr'
|
||||
| 'hr'
|
||||
| 'he'
|
||||
| 'hi'
|
||||
| 'hu'
|
||||
| 'it'
|
||||
| 'ja'
|
||||
@@ -21,10 +25,12 @@ export type AvailableLocale =
|
||||
| 'pl'
|
||||
| 'pt-BR'
|
||||
| 'pt-PT'
|
||||
| 'ro'
|
||||
| 'ru'
|
||||
| 'sq'
|
||||
| 'sr'
|
||||
| 'sv'
|
||||
| 'uk'
|
||||
| 'zh-CN'
|
||||
| 'zh-TW';
|
||||
|
||||
@@ -34,6 +40,10 @@ type AvailableLanguageObject = Record<
|
||||
>;
|
||||
|
||||
export const availableLanguages: AvailableLanguageObject = {
|
||||
bg: {
|
||||
code: 'bg',
|
||||
display: 'Bulgarian',
|
||||
},
|
||||
ca: {
|
||||
code: 'ca',
|
||||
display: 'Català',
|
||||
@@ -58,10 +68,22 @@ export const availableLanguages: AvailableLanguageObject = {
|
||||
code: 'es',
|
||||
display: 'Español',
|
||||
},
|
||||
fi: {
|
||||
code: 'fi',
|
||||
display: 'Finnish',
|
||||
},
|
||||
fr: {
|
||||
code: 'fr',
|
||||
display: 'Français',
|
||||
},
|
||||
he: {
|
||||
code: 'he',
|
||||
display: 'Hebrew',
|
||||
},
|
||||
hi: {
|
||||
code: 'hi',
|
||||
display: 'Hindi',
|
||||
},
|
||||
hr: {
|
||||
code: 'hr',
|
||||
display: 'Hrvatski',
|
||||
@@ -110,6 +132,10 @@ export const availableLanguages: AvailableLanguageObject = {
|
||||
code: 'el',
|
||||
display: 'Ελληνικά',
|
||||
},
|
||||
ro: {
|
||||
code: 'ro',
|
||||
display: 'Romanian',
|
||||
},
|
||||
ru: {
|
||||
code: 'ru',
|
||||
display: 'pусский',
|
||||
@@ -130,6 +156,10 @@ export const availableLanguages: AvailableLanguageObject = {
|
||||
code: 'ko',
|
||||
display: '한국어',
|
||||
},
|
||||
uk: {
|
||||
code: 'uk',
|
||||
display: 'українська мова',
|
||||
},
|
||||
'zh-TW': {
|
||||
code: 'zh-TW',
|
||||
display: '繁體中文',
|
||||
|
||||
@@ -19,7 +19,7 @@ const useDeepLinks = ({
|
||||
useEffect(() => {
|
||||
if (
|
||||
/iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
(navigator.userAgent === 'MacIntel' && navigator.maxTouchPoints > 1)
|
||||
(navigator.userAgent.includes('Mac') && navigator.maxTouchPoints > 1)
|
||||
) {
|
||||
setReturnedPlexUrl(iOSPlexUrl);
|
||||
setReturnedPlexUrl4k(iOSPlexUrl4k);
|
||||
|
||||
@@ -55,6 +55,7 @@ const globalMessages = defineMessages({
|
||||
noresults: 'No results.',
|
||||
open: 'Open',
|
||||
resolved: 'Resolved',
|
||||
specials: 'Specials',
|
||||
});
|
||||
|
||||
export default globalMessages;
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
"components.PermissionEdit.viewrequests": "الإطلاع على الطلبات",
|
||||
"components.PermissionEdit.viewrequestsDescription": "إعطاء صلاحية بالإطلاع على جميع الطلبات المقدمة من قبل المستخدمين.",
|
||||
"components.PersonDetails.alsoknownas": "أيضا يُعرف بإسم: {names}",
|
||||
"components.PersonDetails.appearsin": "المظهر",
|
||||
"components.PersonDetails.appearsin": "الظهور",
|
||||
"components.PersonDetails.ascharacter": "{character} شارك بِدوْر",
|
||||
"components.PersonDetails.birthdate": "ولد في {birthdate}",
|
||||
"components.PersonDetails.crewmember": "عضو",
|
||||
@@ -673,7 +673,7 @@
|
||||
"components.Settings.plexlibraries": "مكتبات بليكس",
|
||||
"components.Settings.noDefaultServer": "على الأقل {serverType} سيرفر واحد يجب أن يكون معدا كإفتراضي لإتاحة تنفيذ طلبات الـ {mediaType}.",
|
||||
"components.Settings.plexsettings": "إعدادات بليكس",
|
||||
"components.Settings.serviceSettingsDescription": "قم بإعداد {serverType} سيرفراتك بالإسفل. تستطيع الاتصال بأكثر من سيرفر {serverType} ولكن إثنان فقط يمكن إعدادهما كإفتراضيين واحد لمحتوى الفور كي والاخر لغير الفور كي. الذين يملكون إذونات مسؤول بإمكانهم تجاوز السيرفر المخصص لتنفيذ الطلبات الجديدة قبل الموافقة.",
|
||||
"components.Settings.serviceSettingsDescription": "قم بإعداد {serverType} بالإسفل.تستطيع الاتصال بأكثر من سيرفر {serverType} ,ولكن إثنان فقط يمكن إعدادهما كإفتراضيين (واحد لجودة الفور كي والأخر لغير جودة الفور كي). أصحاب الصلاحيات الإدارية بإمكانهم تجاوز السيرفر المستخدم قبل تأكيدهم لأي طلب محتوى جديد.",
|
||||
"components.Settings.serverpresetManualMessage": "ضبط يدوي",
|
||||
"components.Settings.sonarrsettings": "إعدادات سونار",
|
||||
"components.Settings.tautulliSettingsDescription": "بشكل إختياري أضبط إعدادات سيرفرك الخاص بـ Tautulli.أوفرسيرر سيقوم بجلب بيانات سجل المشاهدة لمحتوى بليكس من Tautulli.",
|
||||
@@ -1232,5 +1232,11 @@
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "يجب تقديم عنوان.",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "{keywordTitle} الأفلام",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "قم بتوفير معرّف كلمات بحث رئيسية من (TMDB)",
|
||||
"components.MovieDetails.imdbuserscore": "تقييم مستخدمين IMDB"
|
||||
"components.MovieDetails.imdbuserscore": "تقييم مستخدمين IMDB",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "صوت التنبيه",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "الجهاز الإفتراضي",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "نوع مسلسل الإنمي",
|
||||
"components.Settings.SonarrModal.seriesType": "نوع المسلسل",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "صوت التنبيه",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "الجهاز الإفتراضي"
|
||||
}
|
||||
|
||||
1242
src/i18n/locale/bg.json
Normal file
1242
src/i18n/locale/bg.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -191,7 +191,7 @@
|
||||
"components.Discover.TvGenreSlider.tvgenres": "Gèneres de Sèries",
|
||||
"components.Discover.TvGenreList.seriesgenres": "Gèneres de Sèries",
|
||||
"components.Discover.StudioSlider.studios": "Estudis",
|
||||
"components.Discover.NetworkSlider.networks": "Emissors",
|
||||
"components.Discover.NetworkSlider.networks": "Plataformes",
|
||||
"components.Discover.MovieGenreSlider.moviegenres": "Gèneres de Pel·lícules",
|
||||
"components.Discover.MovieGenreList.moviegenres": "Gèneres de Pel·lícules",
|
||||
"components.Discover.DiscoverTvLanguage.languageSeries": "Sèries en {language}",
|
||||
@@ -397,7 +397,7 @@
|
||||
"components.TvDetails.originaltitle": "Títol original",
|
||||
"components.TvDetails.originallanguage": "Idioma original",
|
||||
"components.TvDetails.nextAirDate": "Pròxima data d'emissió",
|
||||
"components.TvDetails.network": "{networkCount, plural, one {Emissor} other {Emissors}}",
|
||||
"components.TvDetails.network": "{networkCount, plural, one {Plataforma} other {Plataformes}}",
|
||||
"components.TvDetails.firstAirDate": "Primera data d'emissió",
|
||||
"components.TvDetails.episodeRuntimeMinutes": "{runtime} minuts",
|
||||
"components.TvDetails.episodeRuntime": "Duració de l'episodi",
|
||||
@@ -481,7 +481,7 @@
|
||||
"components.Settings.SonarrModal.validationNameRequired": "Heu de proporcionar un nom de servidor",
|
||||
"components.Settings.SonarrModal.validationLanguageProfileRequired": "Heu de seleccionar un perfil d'idioma",
|
||||
"components.Settings.SonarrModal.validationHostnameRequired": "Heu de proporcionar un nom d’amfitrió o una adreça IP vàlides",
|
||||
"components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "L'URL base no pot acabar amb una barra inclinada final",
|
||||
"components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "L'URL base no ha d'acabar amb una barra inclinada final",
|
||||
"components.Settings.SonarrModal.validationBaseUrlLeadingSlash": "L'URL base ha de tenir una barra inclinada",
|
||||
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "L'URL no pot acabar amb una barra inclinada final",
|
||||
"components.Settings.SonarrModal.validationApplicationUrl": "Heu de proporcionar un URL vàlid",
|
||||
@@ -1119,7 +1119,7 @@
|
||||
"components.Discover.CreateSlider.needresults": "Cal tenir almenys 1 resultat.",
|
||||
"components.Discover.CreateSlider.nooptions": "Sense resultats.",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "Proporciona un ID de categoria TMDB",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Proporciona l'ID d'emissor TMDB",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Proporciona l'ID de la plataforma TMDB",
|
||||
"components.Discover.CreateSlider.providetmdbstudio": "Proporciona l'ID d'estudi TMDB",
|
||||
"components.Discover.CreateSlider.searchGenres": "Cercar per gènere…",
|
||||
"components.Discover.CreateSlider.searchKeywords": "Cercar per paraules clau…",
|
||||
@@ -1151,7 +1151,7 @@
|
||||
"components.Discover.networks": "Emissors",
|
||||
"components.Discover.resetwarning": "Restablir tots els controls lliscants al valor predeterminat. Això també suprimirà els controls lliscants personalitzats!",
|
||||
"components.Discover.tmdbmoviekeyword": "Paraula clau de pel·lícula TMDB",
|
||||
"components.Discover.tmdbnetwork": "Emissors TMDB",
|
||||
"components.Discover.tmdbnetwork": "Plataformes TMDB",
|
||||
"components.Discover.FilterSlideover.tmdbuserscore": "Puntuació d'usuaris TMDB",
|
||||
"components.Discover.tvgenres": "Gèneres de sèries",
|
||||
"components.Discover.DiscoverTvKeyword.keywordSeries": "Sèries {keywordTitle}",
|
||||
@@ -1224,5 +1224,19 @@
|
||||
"components.StatusBadge.seasonepisodenumber": "S{seasonNumber}E{episodeNumber}",
|
||||
"components.Settings.SettingsJobsCache.availability-sync": "Sincronització de disponibilitat de contingut",
|
||||
"components.Discover.tmdbmoviestreamingservices": "Serveis de transmissió de pel·lícules TMDB",
|
||||
"components.Discover.tmdbtvstreamingservices": "Serveis de transmissió de TV TMDB"
|
||||
"components.Discover.tmdbtvstreamingservices": "Serveis de transmissió de TV TMDB",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "Recompte de vots dels usuaris de TMDB",
|
||||
"components.Discover.FilterSlideover.voteCount": "Número de vots entre {minValue} i {maxValue}",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "So per a les notificacions",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Dispositiu per defecte",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "So per a les notificacions",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Tipus d'Anime",
|
||||
"components.Settings.SonarrModal.seriesType": "Tipus de sèrie",
|
||||
"components.Settings.SonarrModal.tagRequests": "Sol·licituds d'etiquetes",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Dispositiu per defecte",
|
||||
"i18n.collection": "Col·lecció",
|
||||
"components.MovieDetails.imdbuserscore": "Puntuació dels usuaris de IMDB",
|
||||
"components.Settings.RadarrModal.tagRequests": "Sol·licituds d'etiqueta",
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Automàticament afegeix una etiqueta addicional amb el nom d'usuari i nom complet del sol·licitant",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Automàticament afegeix una etiqueta addicional amb el nom d'usuari i nom complet del sol·licitant"
|
||||
}
|
||||
|
||||
@@ -784,7 +784,7 @@
|
||||
"components.Settings.externalUrl": "Externí adresa URL",
|
||||
"components.Settings.hostname": "Název hostitele nebo IP adresa",
|
||||
"components.Settings.manualscan": "Manuální skenování knihovny",
|
||||
"components.Settings.plexlibrariesDescription": "Knihovny Overseerr vyhledává tituly. Nastavte a uložte nastavení připojení k systému Plex a poté klikněte na tlačítko níže, pokud nejsou v seznamu uvedeny žádné knihovny.",
|
||||
"components.Settings.plexlibrariesDescription": "Knihovny, ve kterých Overseerr vyhledává tituly. Nastavte a uložte nastavení připojení k systému Plex a poté klikněte na tlačítko níže, pokud nejsou v seznamu uvedeny žádné knihovny.",
|
||||
"components.Settings.serverpresetLoad": "Stisknutím tlačítka načtete dostupné servery",
|
||||
"components.Settings.toastTautulliSettingsFailure": "Při ukládání nastavení Tautulli se něco pokazilo.",
|
||||
"components.Settings.webAppUrl": "<WebAppLink>Webová aplikace</WebAppLink> Adresa URL",
|
||||
@@ -836,7 +836,7 @@
|
||||
"components.Settings.noDefault4kServer": "Server 4K {serverType} musí být označen jako výchozí, aby uživatelé mohli odesílat požadavky 4K {mediaType}.",
|
||||
"components.Settings.noDefaultNon4kServer": "Pokud máte pouze jeden server {serverType} pro obsah jiný než 4K i 4K (nebo pokud stahujete pouze obsah 4K), váš server {serverType} by <strong>neměl</strong> být označen jako server 4K.",
|
||||
"components.Settings.noDefaultServer": "Aby mohly být zpracovány požadavky typu {mediaType}, musí být alespoň jeden server typu {serverType} označen jako výchozí.",
|
||||
"components.Settings.plexsettingsDescription": "Knihovny Overseerr vyhledává tituly. Nastavte a uložte nastavení připojení k systému Plex a poté klikněte na tlačítko níže, pokud nejsou v seznamu uvedeny žádné knihovny.",
|
||||
"components.Settings.plexsettingsDescription": "Nakonfigurujte nastavení pro váš server Plex. Overseerr prohledá vaše knihovny Plex, aby zjistil dostupnost obsahu.",
|
||||
"components.Settings.toastPlexRefresh": "Získání seznamu serverů z aplikace Plex…",
|
||||
"components.Settings.toastPlexRefreshSuccess": "Seznam serverů Plex úspěšně načten!",
|
||||
"components.UserList.passwordinfodescription": "Nakonfigurujte adresu URL aplikace a povolte e-mailová oznámení, která umožní automatické generování hesla.",
|
||||
@@ -1194,7 +1194,7 @@
|
||||
"components.Settings.SettingsMain.applicationurl": "Adresa URL aplikace",
|
||||
"components.Settings.SettingsMain.cacheImages": "Povolení ukládání obrázků do mezipaměti",
|
||||
"components.Settings.SettingsMain.cacheImagesTip": "Ukládání obrázků z externích zdrojů do mezipaměti (vyžaduje značné množství místa na disku)",
|
||||
"components.Settings.SettingsMain.csrfProtection": "Povolení ochrany CSRF",
|
||||
"components.Settings.SettingsMain.csrfProtection": "Povolit ochranu CSRF",
|
||||
"components.Settings.SettingsMain.csrfProtectionHoverTip": "Toto nastavení NEPOVOLUJTE, pokud nerozumíte tomu, co děláte!",
|
||||
"components.Settings.SettingsMain.csrfProtectionTip": "Nastavení externího přístupu k rozhraní API pouze pro čtení (vyžaduje protokol HTTPS)",
|
||||
"components.Settings.SettingsMain.general": "Obecné",
|
||||
@@ -1231,5 +1231,12 @@
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "Počet hlasů uživatelů TMDB",
|
||||
"components.Discover.tmdbmoviestreamingservices": "Filmové streamovací služby TMDB",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Automatické přidání dodatočné značky s ID uživatele a zobrazovaným jménem žadatele",
|
||||
"components.Discover.tmdbtvstreamingservices": "Televizní streamovací služby TMDB"
|
||||
"components.Discover.tmdbtvstreamingservices": "Televizní streamovací služby TMDB",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Zvuk upozornění",
|
||||
"components.MovieDetails.imdbuserscore": "Uživatelské skóre IMDB",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Zvuk upozornění",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Typ anime série",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Výchozí zařízení",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Výchozí zařízení",
|
||||
"components.Settings.SonarrModal.seriesType": "Typ série"
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"components.MovieDetails.markavailable": "Markér som Tilgængelig",
|
||||
"components.MovieDetails.originallanguage": "Originalsprog",
|
||||
"components.Login.signinwithoverseerr": "Brug din {applicationTitle} konto",
|
||||
"components.MovieDetails.MovieCast.fullcast": "Medvirkende",
|
||||
"components.MovieDetails.MovieCast.fullcast": "Fuld rolleliste",
|
||||
"components.MovieDetails.MovieCrew.fullcrew": "Filmstab",
|
||||
"components.MovieDetails.budget": "Budget",
|
||||
"components.MovieDetails.overview": "Overblik",
|
||||
@@ -539,7 +539,7 @@
|
||||
"components.Settings.Notifications.validationSmtpPortRequired": "Du skal angive et gyldigt port-nummer",
|
||||
"components.Settings.Notifications.webhookUrl": "Webhook URL",
|
||||
"components.Settings.Notifications.webhookUrlTip": "Opret en<DiscordWebhookLink>webhook integration</DiscordWebhookLink> til din server",
|
||||
"components.Settings.RadarrModal.baseUrl": "URL Base",
|
||||
"components.Settings.RadarrModal.baseUrl": "URL Kilde",
|
||||
"components.Settings.RadarrModal.create4kradarr": "Tilføj Ny 4K Radarr Server",
|
||||
"components.Settings.RadarrModal.createradarr": "Tilføj Ny Radarr Server",
|
||||
"components.Settings.RadarrModal.default4kserver": "Standard 4K Server",
|
||||
@@ -625,7 +625,7 @@
|
||||
"components.Settings.SettingsLogs.label": "Label",
|
||||
"components.Settings.SettingsLogs.level": "Alvorlighed",
|
||||
"components.Settings.SettingsLogs.logDetails": "Loginformation",
|
||||
"components.Settings.SonarrModal.baseUrl": "URL Base",
|
||||
"components.Settings.SonarrModal.baseUrl": "URL Kilde",
|
||||
"components.Settings.SonarrModal.create4ksonarr": "Tilføj Ny 4K Sonarr Server",
|
||||
"components.Settings.SonarrModal.loadingprofiles": "Indlæser kvalitetsprofiler…",
|
||||
"components.Settings.manualscan": "Manuel Biblioteksskanning",
|
||||
@@ -794,7 +794,7 @@
|
||||
"components.Setup.configureplex": "Konfigurér Plex",
|
||||
"components.Settings.validationPortRequired": "Du skal angive et gyldigt port-nummer",
|
||||
"components.Setup.configureservices": "Konfigurér Tjenester",
|
||||
"components.Setup.continue": "Fortsæt",
|
||||
"components.Setup.continue": "Videre",
|
||||
"components.Setup.finish": "Fuldfør Opsætning",
|
||||
"components.Setup.finishing": "Færdiggører…",
|
||||
"components.Setup.loginwithplex": "Log in med Plex",
|
||||
@@ -1231,5 +1231,12 @@
|
||||
"components.Settings.SonarrModal.tagRequests": "Tag forespørgsler",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Tilføj automatisk et ekstra tag med forespørgerens bruger ID og viste navn",
|
||||
"i18n.collection": "Samling",
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Tilføj automatisk et ekstra tag med forespørgerens bruger id og viste navn"
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Tilføj automatisk et ekstra tag med forespørgerens bruger id og viste navn",
|
||||
"components.MovieDetails.imdbuserscore": "IMDB Bruger Score",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Anime Serie Type",
|
||||
"components.Settings.SonarrModal.seriesType": "Serie Type",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Enhedsstandard",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Notifikationslyd",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Enhedsstandard",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Notifikationslyd"
|
||||
}
|
||||
|
||||
@@ -1231,5 +1231,12 @@
|
||||
"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.Settings.RadarrModal.tagRequests": "Anfragen taggen",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Benachrichtigungston",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Gerätestandard",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Art der Anime-Serie",
|
||||
"components.Settings.SonarrModal.seriesType": "Serientyp",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Benachrichtigungston",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Gerätestandard"
|
||||
}
|
||||
|
||||
@@ -1232,5 +1232,11 @@
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.discordId": "Αναγνωριστικό χρήστη Discord",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip": "Ζητήστε αυτόματα σειρές που βρίσκονται στη <PlexWatchlistSupportLink>λίστα παρακολούθησης του Plex</PlexWatchlistSupportLink>",
|
||||
"components.UserProfile.plexwatchlist": "Λίστα παρακολούθησης Plex",
|
||||
"components.MovieDetails.imdbuserscore": "Βαθμολογία χρηστών IMDB"
|
||||
"components.MovieDetails.imdbuserscore": "Βαθμολογία χρηστών IMDB",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Τύπος σειράς άνιμε",
|
||||
"components.Settings.SonarrModal.seriesType": "Τύπος σειράς",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Ήχος ειδοποίησης",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Προεπιλογή συσκευής",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Ήχος ειδοποίησης",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Προεπιλογή συσκευής"
|
||||
}
|
||||
|
||||
@@ -471,7 +471,6 @@
|
||||
"components.RequestModal.cancel": "Cancel Request",
|
||||
"components.RequestModal.edit": "Edit Request",
|
||||
"components.RequestModal.errorediting": "Something went wrong while editing the request.",
|
||||
"components.RequestModal.extras": "Extras",
|
||||
"components.RequestModal.numberofepisodes": "# of Episodes",
|
||||
"components.RequestModal.pending4krequest": "Pending 4K Request",
|
||||
"components.RequestModal.pendingapproval": "Your request is pending approval.",
|
||||
@@ -558,8 +557,10 @@
|
||||
"components.Settings.Notifications.NotificationsPushover.accessToken": "Application API Token",
|
||||
"components.Settings.Notifications.NotificationsPushover.accessTokenTip": "<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Overseerr",
|
||||
"components.Settings.Notifications.NotificationsPushover.agentenabled": "Enable Agent",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Device Default",
|
||||
"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover notification settings failed to save.",
|
||||
"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Notification Sound",
|
||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed": "Pushover test notification failed to send.",
|
||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending": "Sending Pushover test notification…",
|
||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess": "Pushover test notification sent!",
|
||||
@@ -766,6 +767,7 @@
|
||||
"components.Settings.SettingsJobsCache.nextexecution": "Next Execution",
|
||||
"components.Settings.SettingsJobsCache.plex-full-scan": "Plex Full Library Scan",
|
||||
"components.Settings.SettingsJobsCache.plex-recently-added-scan": "Plex Recently Added Scan",
|
||||
"components.Settings.SettingsJobsCache.plex-refresh-token": "Plex Refresh Token",
|
||||
"components.Settings.SettingsJobsCache.plex-watchlist-sync": "Plex Watchlist Sync",
|
||||
"components.Settings.SettingsJobsCache.process": "Process",
|
||||
"components.Settings.SettingsJobsCache.radarr-scan": "Radarr Scan",
|
||||
@@ -1104,6 +1106,7 @@
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.user": "User",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "You must provide a valid Discord user ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Device Default",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your user account",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Discord notification settings failed to save.",
|
||||
@@ -1127,6 +1130,7 @@
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Silently",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Notification Sound",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram notification settings failed to save.",
|
||||
|
||||
@@ -1232,5 +1232,11 @@
|
||||
"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.Settings.SonarrModal.animeSeriesType": "Tipo de anime",
|
||||
"components.Settings.SonarrModal.seriesType": "Tipo de series",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Sonido para las notificaciones",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Dispositivo predeterminado",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Sonido para las notificaciones",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Dispositivo predeterminado"
|
||||
}
|
||||
|
||||
35
src/i18n/locale/fi.json
Normal file
35
src/i18n/locale/fi.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"components.Discover.CreateSlider.editsuccess": "Liukusäädintä muokattu ja löytömuokkausasetukset tallennettu.",
|
||||
"components.CollectionDetails.numberofmovies": "{count} elokuvaa",
|
||||
"components.Discover.CreateSlider.slidernameplaceholder": "Liukusäätimen nimi",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "<code>{appDataPath}</code> -levyn liittäminen ei onnistunut oikein. Kaikki tiedot poistetaan, kun säilö pysäytetään tai käynnistetään uudelleen.",
|
||||
"components.Discover.DiscoverMovies.sortPopularityDesc": "Suosio laskevassa järjestyksessä",
|
||||
"components.AirDateBadge.airsrelative": "Esitys {relativeTime}",
|
||||
"components.CollectionDetails.overview": "Yleiskatsaus",
|
||||
"components.AirDateBadge.airedrelative": "Esitetty {relativeTime}",
|
||||
"components.Discover.CreateSlider.searchStudios": "Etsi studioita…",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Anna TMDB Network ID",
|
||||
"components.Discover.CreateSlider.addfail": "Uuden liukusäätimen luominen epäonnistui.",
|
||||
"components.CollectionDetails.requestcollection": "Pyydä kokoelma",
|
||||
"components.Discover.DiscoverMovieGenre.genreMovies": "Lajityypin {genre} elokuvat",
|
||||
"components.Discover.DiscoverMovieLanguage.languageMovies": "Elokuvat kielellä {language}",
|
||||
"components.Discover.DiscoverMovies.sortPopularityAsc": "Suosio nousevassa järjestyksessä",
|
||||
"components.Discover.CreateSlider.needresults": "Tarvitaan vähintään 1 tulos.",
|
||||
"components.Discover.CreateSlider.addcustomslider": "Luo mukautettu liukusäädin",
|
||||
"components.Discover.CreateSlider.editSlider": "Muokkaa liukusäädintä",
|
||||
"components.Discover.CreateSlider.validationDatarequired": "Sinun täytyy antaa datan arvo.",
|
||||
"components.Discover.CreateSlider.providetmdbstudio": "Anna TMDB Studio ID",
|
||||
"components.Discover.CreateSlider.searchGenres": "Etsi tyylilajeja…",
|
||||
"components.Discover.CreateSlider.editfail": "Liukusäätimen muokkaus epäonnistui.",
|
||||
"components.Discover.CreateSlider.starttyping": "Aloita kirjoittaminen etsiäksesi.",
|
||||
"components.Discover.CreateSlider.addSlider": "Lisää liukusäädin",
|
||||
"components.CollectionDetails.requestcollection4k": "Pyydä kokoelma 4K-laadulla",
|
||||
"components.Discover.CreateSlider.providetmdbsearch": "Anna hakukysely",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "Anna TMDB Keyword ID",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "{keywordTitle} elokuvat",
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "Sinun tulee antaa nimi.",
|
||||
"components.Discover.CreateSlider.nooptions": "Ei tuloksia.",
|
||||
"components.Discover.CreateSlider.searchKeywords": "Etsi avainsanoja…",
|
||||
"components.Discover.DiscoverMovies.discovermovies": "Elokuvat",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "Anna TMDB Genre ID"
|
||||
}
|
||||
@@ -61,7 +61,7 @@
|
||||
"components.Settings.RadarrModal.port": "Port",
|
||||
"components.Settings.RadarrModal.qualityprofile": "Profil de qualité",
|
||||
"components.Settings.RadarrModal.rootfolder": "Dossier racine",
|
||||
"components.Settings.RadarrModal.selectMinimumAvailability": "Sélectionner une disponibilté minimale",
|
||||
"components.Settings.RadarrModal.selectMinimumAvailability": "Sélectionner une disponibilité minimale",
|
||||
"components.Settings.RadarrModal.selectQualityProfile": "Sélectionner un profil qualité",
|
||||
"components.Settings.RadarrModal.selectRootFolder": "Sélectionner un dossier racine",
|
||||
"components.Settings.RadarrModal.server4k": "Serveur 4K",
|
||||
@@ -162,7 +162,7 @@
|
||||
"i18n.tvshows": "Séries",
|
||||
"i18n.unavailable": "Indisponible",
|
||||
"pages.oops": "Oups",
|
||||
"pages.returnHome": "Retourner à l'acceuil",
|
||||
"pages.returnHome": "Retourner à l'accueil",
|
||||
"components.TvDetails.TvCast.fullseriescast": "Casting complet de la série",
|
||||
"components.MovieDetails.MovieCast.fullcast": "Casting complet",
|
||||
"components.Settings.Notifications.emailsettingssaved": "Paramètres de notification par e-mail enregistrés avec succès !",
|
||||
@@ -208,7 +208,7 @@
|
||||
"components.Settings.SettingsAbout.Releases.viewchangelog": "Voir le journal des modifications",
|
||||
"components.Settings.SettingsAbout.Releases.versionChangelog": "Journal des modifications de la version {version}",
|
||||
"components.Settings.SettingsAbout.Releases.releases": "Versions",
|
||||
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Les données de version sont actuellement indisponible.",
|
||||
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Les données de version sont actuellement indisponibles.",
|
||||
"components.Settings.SettingsAbout.Releases.latestversion": "Dernière version",
|
||||
"components.Settings.SettingsAbout.Releases.currentversion": "Actuelle",
|
||||
"components.UserList.importfromplexerror": "Une erreur s'est produite durant l'importation des utilisateurs de Plex.",
|
||||
@@ -976,7 +976,7 @@
|
||||
"components.ManageSlideOver.manageModalMedia4k": "Média(s) 4K",
|
||||
"components.ManageSlideOver.markallseasons4kavailable": "Marquer toutes les saisons comme disponibles en 4K",
|
||||
"components.ManageSlideOver.playedby": "Joué par",
|
||||
"components.Settings.validationUrlTrailingSlash": "L'URL ne doit pas ce terminer par un slash",
|
||||
"components.Settings.validationUrlTrailingSlash": "L'URL ne doit pas se terminer par un slash",
|
||||
"components.Settings.externalUrl": "URL externe",
|
||||
"components.Settings.tautulliApiKey": "Clé API",
|
||||
"components.Settings.tautulliSettings": "Paramètres Tautulli",
|
||||
@@ -994,9 +994,9 @@
|
||||
"components.ManageSlideOver.alltime": "Tout le temps",
|
||||
"components.ManageSlideOver.manageModalMedia": "Média(s)",
|
||||
"components.ManageSlideOver.markallseasonsavailable": "Marquer toutes les saisons comme disponibles",
|
||||
"components.Settings.validationUrlBaseTrailingSlash": "L'URL de base ne doit pas ce terminer par un slash",
|
||||
"components.Settings.validationUrlBaseTrailingSlash": "L'URL de base ne doit pas se terminer par un slash",
|
||||
"components.Settings.tautulliSettingsDescription": "Configuration optionnelle pour votre serveur Tautulli. Overseerr va récupérer l'historique de visionnage de votre Plex depuis Tautulli.",
|
||||
"components.UserList.newplexsigninenabled": "L'option <strong>Autoriser nouvelle connexion Plex</strong> est actuellement activée. Les utilisateurs Plex disposant d'un accès à la librairie n'ont pas besoin d'être importés pour pouvoir ce connecter.",
|
||||
"components.UserList.newplexsigninenabled": "L'option <strong>Autoriser nouvelle connexion Plex</strong> est actuellement activée. Les utilisateurs Plex disposant d'un accès à la librairie n'ont pas besoin d'être importés pour pouvoir se connecter.",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.discordId": "ID utilisateur Discord",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip": "Le <FindDiscordIdLink>numéro d'identification à plusieurs chiffres</FindDiscordIdLink> est associé avec votre compte Discord",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "Vous devez fournir un ID utilisateur Discord valide",
|
||||
@@ -1191,7 +1191,7 @@
|
||||
"components.Settings.SettingsMain.region": "Région à découvrir",
|
||||
"components.Settings.SettingsMain.regionTip": "Filtrer le contenu par disponibilité régionale",
|
||||
"components.Settings.SettingsMain.trustProxy": "Activer la prise en charge proxy",
|
||||
"components.Settings.SettingsMain.trustProxyTip": "Permettre Overseerr à enregistrer correctement les adresses IP des clients derrière un proxy",
|
||||
"components.Settings.SettingsMain.trustProxyTip": "Permettre à Overseerr d'enregistrer correctement les adresses IP des clients derrière un proxy",
|
||||
"components.Settings.SettingsMain.applicationTitle": "Nom de l'application",
|
||||
"components.Settings.SettingsMain.csrfProtectionTip": "Définir l'accès à l'API externe en lecture seule (nécessite HTTPS)",
|
||||
"components.Settings.SettingsMain.cacheImagesTip": "Met en cache localement et utilise des images optimisées (nécessite une quantité considérable d'espace disque)",
|
||||
@@ -1232,5 +1232,11 @@
|
||||
"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.MovieDetails.imdbuserscore": "Note Utilisateurs"
|
||||
"components.MovieDetails.imdbuserscore": "Note Utilisateurs",
|
||||
"components.Settings.SonarrModal.seriesType": "Type de série",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Types d'anime",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Appareil par défaut",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Appareil par défaut",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Son de notification",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Son de notification"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"components.ManageSlideOver.alltime": "כל הזמנים",
|
||||
"components.Login.validationemailrequired": "חובה לספק כתובת מייל חוקית",
|
||||
"components.NotificationTypeSelector.userissuereopenedDescription": "קבל התראה כשבעיות שפתחת נפתחות מחדש.",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "ה <code>{appDataPath}</code> אחסון לא הוגדר כראוי. כל המידע יוסר כאשר הקונטיינר יעצור או יותחל מחדש.",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "רכיב האחסון <code>{appDataPath}</code> לא הוגדר כראוי. כל המידע יוסר כאשר הקונטיינר יעצור או יותחל מחדש.",
|
||||
"components.CollectionDetails.overview": "תצוגה כללית",
|
||||
"components.CollectionDetails.numberofmovies": "{כמות} סרטים",
|
||||
"components.CollectionDetails.requestcollection": "אוסף בקשות",
|
||||
@@ -135,5 +135,41 @@
|
||||
"components.Login.loginerror": "משהו השתבש בזמן ההתחברות.",
|
||||
"components.Login.password": "סיסמה",
|
||||
"components.Login.signin": "התחברות",
|
||||
"components.Login.validationpasswordrequired": "חובה לכתוב סיסמה"
|
||||
"components.Login.validationpasswordrequired": "חובה לכתוב סיסמה",
|
||||
"components.Discover.CreateSlider.editsuccess": "ערוך סליידרהגדרות התאמה אישית שמורות.",
|
||||
"components.Discover.CreateSlider.slidernameplaceholder": "שם הסליידר",
|
||||
"components.Discover.DiscoverMovies.sortPopularityDesc": "פופולאריות יורדץ",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "דירוג TMDB עולה",
|
||||
"components.Discover.CreateSlider.searchStudios": "חפש אולפנים…",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "תאריך שחרור יורד",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "הזמן מזהה רשת TMDB",
|
||||
"components.Discover.CreateSlider.addfail": "שגיאה ביצירת סליידר.",
|
||||
"components.Discover.DiscoverMovies.sortPopularityAsc": "פופולאריות עולה",
|
||||
"components.Discover.CreateSlider.needresults": "חייב שתהיה לפחות תוצאה אחת.",
|
||||
"components.Discover.CreateSlider.addcustomslider": "צור סליידר מותאם אישית",
|
||||
"components.Discover.CreateSlider.editSlider": "ערוך סליידר",
|
||||
"components.Discover.CreateSlider.validationDatarequired": "עליך לספק ערך.",
|
||||
"components.Discover.DiscoverTv.discovertv": "סדרה",
|
||||
"components.Discover.DiscoverSliderEdit.deletefail": "שגיאה במחיקת סליידר.",
|
||||
"components.Discover.CreateSlider.providetmdbstudio": "הזן מזהה אולפן TMDB",
|
||||
"components.Discover.DiscoverMovies.sortTitleDesc": "כותר (ת-א) יורד",
|
||||
"components.Discover.CreateSlider.searchGenres": "חפש ז'אנרים…",
|
||||
"components.Discover.CreateSlider.editfail": "שגיאה בעריכת סליידר.",
|
||||
"components.Discover.CreateSlider.starttyping": "התחל לכתוב כדי לחפש.",
|
||||
"components.Discover.DiscoverSliderEdit.enable": "שנה נראות",
|
||||
"components.Discover.CreateSlider.addSlider": "הוסף סליידר",
|
||||
"components.Discover.CreateSlider.providetmdbsearch": "הזן מילת חיפוש",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "הזן מילת חיפוש TMDB",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "סרטי {keywordTitle}",
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "עליך לספק כותרת.",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "תאריך שחרור עולה",
|
||||
"components.Discover.CreateSlider.nooptions": "אין תוצאות.",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "דירוג TMDB יורד",
|
||||
"components.Discover.CreateSlider.searchKeywords": "חפש מילות מפתח…",
|
||||
"components.Discover.CreateSlider.addsuccess": "צור סליידר חדש והגדרות התאמה אישית שמורות.",
|
||||
"components.Discover.DiscoverSliderEdit.deletesuccess": "סליידר נמחק בהצלחה.",
|
||||
"components.Discover.DiscoverMovies.discovermovies": "סרטים",
|
||||
"components.Discover.DiscoverMovies.sortTitleAsc": "כותר (א-ת) עולה",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "הזן מזהה ז'אנר TMDB",
|
||||
"components.Discover.DiscoverSliderEdit.remove": "הסר"
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
"components.Discover.DiscoverTvGenre.genreSeries": "{genre} serije",
|
||||
"components.Discover.DiscoverTvLanguage.languageSeries": "{language} serije",
|
||||
"components.Discover.DiscoverWatchlist.discoverwatchlist": "Tvoj Plex popis gledanja",
|
||||
"components.Discover.MovieGenreList.moviegenres": "Filmski žanrovi",
|
||||
"components.Discover.StudioSlider.studios": "Studio",
|
||||
"components.Discover.TvGenreList.seriesgenres": "Serijski žanrovi",
|
||||
"components.Discover.TvGenreSlider.tvgenres": "Serijski žanrovi",
|
||||
"components.Discover.MovieGenreList.moviegenres": "Žanrovi filmova",
|
||||
"components.Discover.StudioSlider.studios": "Studiji",
|
||||
"components.Discover.TvGenreList.seriesgenres": "Žanrovi serija",
|
||||
"components.Discover.TvGenreSlider.tvgenres": "Žanrovi serija",
|
||||
"components.Discover.plexwatchlist": "Tvoj Plex popis gledanja",
|
||||
"components.Discover.popularmovies": "Popularni filmovi",
|
||||
"components.Discover.recentlyAdded": "Nedavno dodani",
|
||||
@@ -33,9 +33,9 @@
|
||||
"components.AirDateBadge.airedrelative": "Emitirano {relativeTime}",
|
||||
"components.AirDateBadge.airsrelative": "Emitiranje {relativeTime}",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "Navedeni <code>{appDataPath}</code> mapirani volumen nije ispravno podešen. Svi podaci će biti izbrisani kada se spremnik (container) zaustavi ili ponovno pokrene.",
|
||||
"components.Discover.DiscoverWatchlist.watchlist": "Plex popis za gledanje",
|
||||
"components.Discover.emptywatchlist": "Filmovi dodani na Vaš <PlexWatchlistSupportLink> popis za gledanje </PlexWatchlistSupportLink> pojaviti će se ovdje.",
|
||||
"components.Discover.MovieGenreSlider.moviegenres": "Filmski žanrovi",
|
||||
"components.Discover.DiscoverWatchlist.watchlist": "Plex popis gledanja",
|
||||
"components.Discover.emptywatchlist": "Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>Plex popis gledanja</PlexWatchlistSupportLink> pojavit će se ovdje.",
|
||||
"components.Discover.MovieGenreSlider.moviegenres": "Žanrovi filmova",
|
||||
"components.Discover.NetworkSlider.networks": "Mreže",
|
||||
"components.Discover.populartv": "Popularne serije",
|
||||
"components.Discover.upcomingtv": "Nadolazeće serije",
|
||||
@@ -67,7 +67,7 @@
|
||||
"components.IssueModal.issueAudio": "Zvuk",
|
||||
"components.IssueModal.issueSubtitles": "Podnaslov",
|
||||
"components.IssueModal.issueVideo": "Video",
|
||||
"components.IssueList.IssueItem.seasons": "{seasonCount, plural, one {sezona} few {sezone} other {sezona}}",
|
||||
"components.IssueList.IssueItem.seasons": "{seasonCount, plural, one {sezona} few {sezone} other {sezone}}",
|
||||
"components.Layout.UserDropdown.myprofile": "Profil",
|
||||
"components.Layout.UserDropdown.requests": "Zahtjevi",
|
||||
"components.Layout.VersionStatus.streamstable": "Overseerr stablina verzija",
|
||||
@@ -78,7 +78,7 @@
|
||||
"components.ManageSlideOver.movie": "film",
|
||||
"components.Login.validationemailrequired": "Moraš zadati valjanju e‑mail adresu",
|
||||
"components.ManageSlideOver.manageModalRequests": "Zahtjevi",
|
||||
"components.ManageSlideOver.manageModalClearMediaWarning": "* Ovo će nepovratno ukloniti sve podatke za ovaj {mediaType}, uključujući sve zahtjeve. Ako ova stavka postoji u vašoj Plex biblioteci, informacije o medijima ponovno će se stvoriti tijekom sljedećeg skeniranja.",
|
||||
"components.ManageSlideOver.manageModalClearMediaWarning": "* Ovo će nepovratno ukloniti sve podatke za {mediaType}, uključujući sve zahtjeve. Ako ova stavka postoji u tvojoj Plex biblioteci, informacije o medijima će se ponovo stvoriti tijekom sljedećeg pretraživanja.",
|
||||
"components.ManageSlideOver.manageModalMedia4k": "4K mediji",
|
||||
"components.ManageSlideOver.manageModalNoRequests": "Nema zahtjeva.",
|
||||
"components.ManageSlideOver.manageModalMedia": "Mediji",
|
||||
@@ -93,13 +93,13 @@
|
||||
"components.MediaSlider.ShowMoreCard.seemore": "Vidi više",
|
||||
"components.MovieDetails.markavailable": "Označi kao dostupno",
|
||||
"components.ManageSlideOver.tvshow": "serije",
|
||||
"components.MovieDetails.productioncountries": "{countryCount, plural, one {zemlja produkcije} few {zemlje produkcije} other {zemalja produkcije}}",
|
||||
"components.MovieDetails.productioncountries": "{countryCount, plural, one {Zemlja produkcije} few {Zemlje produkcije} other {Zemlje produkcije}}",
|
||||
"components.MovieDetails.managemovie": "Upravljaj filmom",
|
||||
"components.MovieDetails.playonplex": "Reproduciraj na Plexu",
|
||||
"components.MovieDetails.overviewunavailable": "Pregled nedostupan.",
|
||||
"components.MovieDetails.reportissue": "Prijavi problem",
|
||||
"components.MovieDetails.revenue": "Prihod",
|
||||
"components.MovieDetails.rtaudiencescore": "Ocjena publike na Rotten Tomatoes",
|
||||
"components.MovieDetails.rtaudiencescore": "Ocjena Rotten Tomatoes publike",
|
||||
"components.MovieDetails.showless": "Prikaži manje",
|
||||
"components.MovieDetails.showmore": "Prikaži više",
|
||||
"components.MovieDetails.similar": "Slični naslovi",
|
||||
@@ -128,7 +128,7 @@
|
||||
"components.IssueList.IssueItem.opened": "Otvoren",
|
||||
"components.IssueList.IssueItem.problemepisode": "Zahvaćena epizoda",
|
||||
"components.IssueList.IssueItem.unknownissuetype": "Nepoznato",
|
||||
"components.IssueList.IssueItem.episodes": "{episodeCount, plural, one {Epizoda} other {Epizode}}",
|
||||
"components.IssueList.IssueItem.episodes": "{episodeCount, plural, one {epizoda} few {epizode} other {epizode}}",
|
||||
"components.IssueList.IssueItem.viewissue": "Prikaz problema",
|
||||
"components.IssueList.showallissues": "Prikaži sve probleme",
|
||||
"components.IssueList.sortAdded": "Najnoviji",
|
||||
@@ -142,7 +142,7 @@
|
||||
"components.IssueModal.CreateIssueModal.season": "Sezona {seasonNumber}",
|
||||
"components.IssueModal.CreateIssueModal.submitissue": "Pošalji problem",
|
||||
"components.IssueModal.CreateIssueModal.toastFailedCreate": "Dogodila se greška prilikom slanja problema.",
|
||||
"components.IssueModal.CreateIssueModal.toastSuccessCreate": "Problem prijavljen za <strong>{title}</strong> je uspješno predan!",
|
||||
"components.IssueModal.CreateIssueModal.toastSuccessCreate": "Izvještaj o problemu za <strong>{title}</strong> je uspješno poslan!",
|
||||
"components.IssueModal.CreateIssueModal.toastviewissue": "Prikaz problema",
|
||||
"components.IssueModal.CreateIssueModal.validationMessageRequired": "Moraš navesti opis",
|
||||
"components.IssueModal.CreateIssueModal.whatswrong": "Što nije u redu?",
|
||||
@@ -166,7 +166,7 @@
|
||||
"components.Login.loginerror": "Dogodila se greška prilikom pokušaja prijave.",
|
||||
"components.Login.signin": "Prijavi se",
|
||||
"components.Login.signingin": "Prijava…",
|
||||
"components.Layout.VersionStatus.commitsbehind": "Verzija ne sadrži {commitsBehind} {commitsBehind, plural, one {promjenu} few {promjene} other {promjena}}",
|
||||
"components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} few {commita} other {commitova}} iza",
|
||||
"components.Login.signinheader": "Prijavi se za nastavak",
|
||||
"components.Login.signinwithoverseerr": "Koristi tvoj {applicationTitle} račun",
|
||||
"components.Login.validationpasswordrequired": "Moraš navesti lozinku",
|
||||
@@ -186,36 +186,36 @@
|
||||
"components.MovieDetails.originallanguage": "Izvorni jezik",
|
||||
"components.MovieDetails.MovieCrew.fullcrew": "Svi suradnici",
|
||||
"components.MovieDetails.physicalrelease": "Fizičko izdanje",
|
||||
"components.MovieDetails.play4konplex": "Reproduciraj u 4K na Plexu",
|
||||
"components.MovieDetails.play4konplex": "Reproduciraj u 4K rezoluciji na Plexu",
|
||||
"components.MovieDetails.recommendations": "Preporuke",
|
||||
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Datum izlaska} other {Datumi izlaska}}",
|
||||
"components.MovieDetails.rtcriticsscore": "Tomatometer na Rotten Tomatoes",
|
||||
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Datum izdanja} few {Datumi izdanja} other {Datumi izdanja}}",
|
||||
"components.MovieDetails.rtcriticsscore": "Rotten Tomatoes Tomatometar",
|
||||
"components.MovieDetails.runtime": "{minutes} min",
|
||||
"components.MovieDetails.studio": "{studioCount, plural, one {studio} few {studija} other {studija}}",
|
||||
"components.MovieDetails.theatricalrelease": "Izdanje u kinima",
|
||||
"components.MovieDetails.tmdbuserscore": "TMDB ocjena korisnika",
|
||||
"components.MovieDetails.viewfullcrew": "Prikaz svih suradnika",
|
||||
"components.MovieDetails.watchtrailer": "Gledaj najavu",
|
||||
"components.NotificationTypeSelector.adminissuecommentDescription": "Primi obavijest kad drugi korisnici komentiraju probleme.",
|
||||
"components.NotificationTypeSelector.adminissuereopenedDescription": "Primi obavijest kad drugi korisnici ponovno otvore probleme.",
|
||||
"components.NotificationTypeSelector.adminissueresolvedDescription": "Primi obavijest kad drugi korisnici riješe probleme.",
|
||||
"components.NotificationTypeSelector.adminissuecommentDescription": "Primi obavijest kada drugi korisnici komentiraju probleme.",
|
||||
"components.NotificationTypeSelector.adminissuereopenedDescription": "Primi obavijest kada drugi korisnici ponovo otvore probleme.",
|
||||
"components.NotificationTypeSelector.adminissueresolvedDescription": "Primi obavijest kada drugi korisnici riješe probleme.",
|
||||
"components.NotificationTypeSelector.issuecomment": "Komentar za problem",
|
||||
"components.NotificationTypeSelector.issuecreated": "Problem prijavljen",
|
||||
"components.NotificationTypeSelector.issuecreatedDescription": "Pošalji obavijest kada se problem prijavi.",
|
||||
"components.NotificationTypeSelector.userissueresolvedDescription": "Primi obavijest kad se tvoji prijavljeni problemi riješe.",
|
||||
"components.NotificationTypeSelector.mediaavailableDescription": "Pošalji obavijesti kada medijski zahtjevi postanu dostupni.",
|
||||
"components.NotificationTypeSelector.mediadeclinedDescription": "Pošalji obavijesti kada su medijski zahtjevi odbijeni.",
|
||||
"components.NotificationTypeSelector.mediaavailableDescription": "Pošalji obavijesti kada zahtjevi za medije postanu dostupni.",
|
||||
"components.NotificationTypeSelector.mediadeclinedDescription": "Pošalji obavijesti kada se zahtjevi za medije odbiju.",
|
||||
"components.NotificationTypeSelector.mediarequested": "Zahtjev čeka odobrenje",
|
||||
"components.NotificationTypeSelector.mediarequestedDescription": "Pošalji obavijesti kada korisnici pošalju nove medijske zahtjeve koji zahtijevaju odobrenje.",
|
||||
"components.NotificationTypeSelector.mediarequestedDescription": "Pošalji obavijesti kada korisnici pošalju nove zahtjeve za medije koji zahtijevaju odobrenje.",
|
||||
"components.NotificationTypeSelector.mediaautorequested": "Zahtjev je automatski poslan",
|
||||
"components.NotificationTypeSelector.mediaavailable": "Zahtjev dostupan",
|
||||
"components.NotificationTypeSelector.mediafailedDescription": "Pošalji obavijesti kada se medijski zahtjevi ne uspiju dodati u Radarr ili Sonarr.",
|
||||
"components.NotificationTypeSelector.userissuecommentDescription": "Primi obavijest kad tvoji prijavljeni problemi dobiju nove komentare.",
|
||||
"components.NotificationTypeSelector.mediaavailable": "Zahtjev je dostupan",
|
||||
"components.NotificationTypeSelector.mediafailedDescription": "Pošalji obavijesti kada se zahtjevi za medije ne uspiju dodati u Radarr ili Sonarr.",
|
||||
"components.NotificationTypeSelector.userissuecommentDescription": "Primi obavijest kada tvoji prijavljeni problemi dobiju nove komentare.",
|
||||
"components.PermissionEdit.autoapprove4kSeries": "Automatsko odobravanje 4K serija",
|
||||
"components.NotificationTypeSelector.usermediafailedDescription": "Primi obavijest kad se medijski zahtjevi ne uspiju dodati u Radarr ili Sonarr.",
|
||||
"components.NotificationTypeSelector.usermediarequestedDescription": "Primi obavijest kad drugi korisnici pošalju nove medijske zahtjeve koji zahtijevaju odobrenje.",
|
||||
"components.NotificationTypeSelector.usermediaAutoApprovedDescription": "Primi obavijest kad drugi korisnici pošalju nove medijske zahtjeve koji se automatski odobravaju.",
|
||||
"components.NotificationTypeSelector.usermediadeclinedDescription": "Primi obavijest kad se tvoji medijski zahtjevi odbiju.",
|
||||
"components.NotificationTypeSelector.usermediafailedDescription": "Primi obavijest kada se zahtjevi za medije ne uspiju dodati u Radarr ili Sonarr.",
|
||||
"components.NotificationTypeSelector.usermediarequestedDescription": "Primi obavijest kada drugi korisnici pošalju nove zahtjeve za medije koji zahtijevaju odobrenje.",
|
||||
"components.NotificationTypeSelector.usermediaAutoApprovedDescription": "Primi obavijest kad drugi korisnici pošalju nove zahtjeve za medije koji se automatski odobravaju.",
|
||||
"components.NotificationTypeSelector.usermediadeclinedDescription": "Primi obavijest kada se tvoji zahtjevi za medije odbiju.",
|
||||
"components.PermissionEdit.adminDescription": "Potpun administratorski pristup. Zaobilazi sve druge provjere dozvola.",
|
||||
"components.PermissionEdit.advancedrequest": "Napredni zahtjevi",
|
||||
"components.PermissionEdit.autoapprove4k": "Automatsko odobravanje 4K",
|
||||
@@ -233,24 +233,24 @@
|
||||
"components.RequestList.RequestItem.seasons": "{seasonCount, plural, one {sezona} few {sezone} other {sezona}}",
|
||||
"components.RequestBlock.seasons": "{seasonCount, plural, one {sezona} few {sezone} other {sezona}}",
|
||||
"components.RequestButton.decline4krequests": "Odbij {requestCount, plural, one {4K zahtjev} few {{requestCount} 4K zahtjeva} other {{requestCount} 4K zahtjeva}}",
|
||||
"components.RequestModal.QuotaDisplay.requiredquotaUser": "Ovaj korisnik treba imati još barem <strong>{seasons}</strong> {seasons, plural, one {jedan zahtjev za sezonu} other {nekoliko zahtjeva za sezone}} kako bi mogao preadti zahtjev za ovu seriju.",
|
||||
"components.RequestModal.QuotaDisplay.requiredquota": "Moraš imati još barem <strong>{seasons}</strong> {seasons, plural, one {zahtjev za sezonu} few {zahtjeva za sezone} other {zahtjeva za sezone}} za slanje zahtjeva za ovu seriju.",
|
||||
"components.RequestModal.QuotaDisplay.requiredquotaUser": "Za slanje zahtjeva za ovu seriju, ovaj korisnik mora imati barem <strong>{seasons}</strong> {seasons, plural, one {preostali zahtjev za sezonu} few {preostala zahtjeva za sezone} other {preostalih zahtjeva za sezone}}.",
|
||||
"components.RequestModal.QuotaDisplay.requiredquota": "Za slanje zahtjeva za ovu seriju moraš imati barem <strong>{seasons}</strong> {seasons, plural, one {preostali zahtjev za sezonu} few {preostala zahtjeva za sezone} other {preostalih zahtjeva za sezone}}.",
|
||||
"components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {sezona} few {sezone} other {sezona}}",
|
||||
"components.RequestModal.requestmovies": "Zatraži {count} {count, plural, one {film} few {filma} other {filmova}}",
|
||||
"components.RequestModal.requestmovies4k": "Zatraži {count} {count, plural, one {film} few {filma} other {filmova}} u 4K",
|
||||
"components.NotificationTypeSelector.mediaAutoApprovedDescription": "Pošalji obavijesti kada korisnici pošalju novi medijski zahtjev koji se automatski odobrava.",
|
||||
"components.NotificationTypeSelector.mediaapproved": "Zahtjev odobren",
|
||||
"components.NotificationTypeSelector.mediaapprovedDescription": "Pošalji obavijesti kada se medijski zahtjev ručno odobri.",
|
||||
"components.NotificationTypeSelector.mediaautorequestedDescription": "Primi obavijest kad se novi medijski zahtjevi automatski podnesu za stavke u tvom Plex popisu gledanja.",
|
||||
"components.NotificationTypeSelector.mediaAutoApprovedDescription": "Pošalji obavijesti kada korisnici pošalju nove zahtjeve za medije koji se automatski odobravaju.",
|
||||
"components.NotificationTypeSelector.mediaapproved": "Zahtjev je odobren",
|
||||
"components.NotificationTypeSelector.mediaapprovedDescription": "Pošalji obavijesti kada se zahtjevi za medije ručno odobre.",
|
||||
"components.NotificationTypeSelector.mediaautorequestedDescription": "Primi obavijest kada se novi zahtjevi za medije automatski pošalju za stavke u tvom Plex popisu gledanja.",
|
||||
"components.NotificationTypeSelector.mediadeclined": "Zahtjev je odbijen",
|
||||
"components.NotificationTypeSelector.mediafailed": "Obrada zahtjeva nije uspjela",
|
||||
"components.NotificationTypeSelector.notificationTypes": "Vrste obavijesti",
|
||||
"components.NotificationTypeSelector.userissuecreatedDescription": "Primi obavijest kad drugi korisnici prijave probleme.",
|
||||
"components.NotificationTypeSelector.userissuereopenedDescription": "Primi obavijest kad se tvoji prijavljeni problemi ponovno otvore.",
|
||||
"components.NotificationTypeSelector.usermediaapprovedDescription": "Primi obavijest kad se tvoji zahtjevi za medije odobre.",
|
||||
"components.NotificationTypeSelector.usermediaavailableDescription": "Primi obavijest kad tvoji medijski zahtjevi postanu dostupni.",
|
||||
"components.NotificationTypeSelector.userissuecreatedDescription": "Primi obavijest kada drugi korisnici prijave probleme.",
|
||||
"components.NotificationTypeSelector.userissuereopenedDescription": "Primi obavijest kada se tvoji prijavljeni problemi ponovno otvore.",
|
||||
"components.NotificationTypeSelector.usermediaapprovedDescription": "Primi obavijest kada se tvoji zahtjevi za medije odobre.",
|
||||
"components.NotificationTypeSelector.usermediaavailableDescription": "Primi obavijest kada tvoji medijski zahtjevi postanu dostupni.",
|
||||
"components.PermissionEdit.admin": "Administrator",
|
||||
"components.PermissionEdit.advancedrequestDescription": "Dozvoli mijenjanje naprednih opcija medijskih zahtjeva.",
|
||||
"components.PermissionEdit.advancedrequestDescription": "Dozvoli mijenjanje naprednih opcija zahtjeva za medije.",
|
||||
"components.PermissionEdit.autoapprove": "Automatsko odobravanje",
|
||||
"components.PermissionEdit.autoapprove4kMovies": "Automatsko odobravanje 4K filmova",
|
||||
"components.PermissionEdit.autoapprove4kDescription": "Dozvoli automatsko odobravanje svih zahtjeva za medije u 4K rezoluciji.",
|
||||
@@ -258,7 +258,7 @@
|
||||
"components.PermissionEdit.autoapproveMovies": "Automatsko odobravanje filmova",
|
||||
"components.PermissionEdit.autoapproveSeries": "Automatsko odobravanje serija",
|
||||
"components.RequestButton.declinerequests": "Odbij {requestCount, plural, one {zahtjev} few {{requestCount} zahtjeva} other {{requestCount} zahtjeva}}",
|
||||
"components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {zahtjev preostalo} other {zahtjeva preostala}}",
|
||||
"components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {0} other {<strong>#</strong>}} {type} {remaining, plural, one {zahtjev preostao} few {zahtjeva preostala} other {zahtjeva preostalo}}",
|
||||
"components.Settings.SettingsJobsCache.editJobScheduleCurrent": "Aktualna učestalost",
|
||||
"components.Settings.SettingsJobsCache.editJobSchedulePrompt": "Nova učestalost",
|
||||
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "{jobScheduleHours, plural, one {Svaki sat} few {Svaka {jobScheduleHours} sata} other {Svakih {jobScheduleHours} sati}}",
|
||||
@@ -364,7 +364,7 @@
|
||||
"components.Settings.menuServices": "Usluge",
|
||||
"components.Settings.menuUsers": "Korisnici",
|
||||
"components.Settings.noDefault4kServer": "4K {serverType} poslužitelj mora biti označen kao zadani kako bi se korisnicima omogućilo slanje zahtjeva za 4K {mediaType}.",
|
||||
"components.Settings.noDefaultServer": "Najmanje jedan {serverType} poslužitelj mora biti označen kao zadani kako bi se zahtjevi za {mediaType} mogli obraditi.",
|
||||
"components.Settings.noDefaultServer": "Barem jedan {serverType} poslužitelj mora biti označen kao zadani kako bi se zahtjevi za {mediaType} mogli obraditi.",
|
||||
"components.Settings.notificationAgentSettingsDescription": "Konfiguriraj i aktiviraj agente obavijesti.",
|
||||
"components.Settings.notifications": "Obavijesti",
|
||||
"components.Settings.notificationsettings": "Postavke obavijesti",
|
||||
@@ -385,7 +385,7 @@
|
||||
"components.Settings.serverpresetLoad": "Pritisni gumb za učitavanje dostupnih polsužitelja",
|
||||
"components.Settings.serverpresetManualMessage": "Ručna konfiguracija",
|
||||
"components.Settings.services": "Usluge",
|
||||
"components.Settings.settingUpPlexDescription": "Za postavljanje Plexa, unesi detalje ručno ili odaberi poslužitelj preuzet s <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Pritisni gumb desno od padajućeg izbornika za dohvaćanje popisa dostupnih poslužitelja.",
|
||||
"components.Settings.settingUpPlexDescription": "Za postavljanje Plexa unesi detalje ručno ili odaberi poslužitelj dohvaćen s <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Pritisni gumb desno od padajućeg izbornika za dohvaćanje popisa dostupnih poslužitelja.",
|
||||
"components.Settings.sonarrsettings": "Sonarr postavke",
|
||||
"components.Settings.ssl": "SSL",
|
||||
"components.Settings.tautulliApiKey": "API ključ",
|
||||
@@ -399,7 +399,7 @@
|
||||
"components.Settings.urlBase": "Osnovni URL",
|
||||
"components.Settings.validationApiKey": "Moraš navesti valjani API ključ",
|
||||
"components.Settings.webpush": "Web Push",
|
||||
"components.Setup.continue": "Nastavi",
|
||||
"components.Setup.continue": "Nastaviti",
|
||||
"components.Setup.finish": "Završi postavljanje",
|
||||
"components.Setup.tip": "Savjet",
|
||||
"components.Setup.welcome": "Overseerr dobrodošlica",
|
||||
@@ -451,8 +451,8 @@
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.general": "Opće",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "Opće postavke",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault": "Zadano ({language})",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filtriraj sadržaj prema izvornom jeziku",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Otkrij jezik",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filtriraj sadržaj po izvornom jeziku",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Jezik otkrivanja",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Plex korisnik",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies": "Automatsko zahtijevanje filmova",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip": "Automatski zatraži filmove na tvom <PlexWatchlistSupportLink>Plex popisu gledanja</PlexWatchlistSupportLink>",
|
||||
@@ -482,7 +482,7 @@
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "Nemaš dozvole za mijenjenje lozinke ovog korisnika.",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.password": "Lozinka",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Dogodila se greška prilikom spremanja lozinke.",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Dogodila se greška prilikom spremanja lozinke. Je li vaša aktualna lozinka bila ispravno upisana?",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Dogodila se greška prilikom spremanja lozinke. Je li tvoja aktualna lozinka ispravno upisana?",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Lozinka je uspješno spremljena!",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "Moraš navesti tvoju aktualnu lozinku",
|
||||
"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "Moraš navesti novu lozinku",
|
||||
@@ -494,10 +494,10 @@
|
||||
"components.UserProfile.UserSettings.menuNotifications": "Obavijesti",
|
||||
"components.UserProfile.UserSettings.menuPermissions": "Dozvole",
|
||||
"components.UserProfile.UserSettings.unauthorizedDescription": "Nemaš dozvole za mijenjenje postavki ovog korisnika.",
|
||||
"components.UserProfile.emptywatchlist": "Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>popis gledanja na Plexu</PlexWatchlistSupportLink> pojavit će se ovdje.",
|
||||
"components.UserProfile.emptywatchlist": "Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>Plex popis gledanja</PlexWatchlistSupportLink> pojavit će se ovdje.",
|
||||
"components.UserProfile.movierequests": "Zahtjevi za filmove",
|
||||
"components.UserProfile.pastdays": "{type} (zadnjih {days} dana)",
|
||||
"components.UserProfile.plexwatchlist": "Popis gledanja na Plexu",
|
||||
"components.UserProfile.plexwatchlist": "Plex popis gledanja",
|
||||
"components.UserProfile.seriesrequest": "Zahtjevi za serije",
|
||||
"components.UserProfile.totalrequests": "Ukupno zahtjeva",
|
||||
"components.UserProfile.unlimited": "Neograničeno",
|
||||
@@ -538,7 +538,7 @@
|
||||
"components.PermissionEdit.viewissues": "Prikaz problema",
|
||||
"components.PermissionEdit.viewrecent": "Prikaz nedavno dodanih",
|
||||
"components.PermissionEdit.viewrequests": "Prikaz zahtjeva",
|
||||
"components.PermissionEdit.viewwatchlists": "Prikaz Plex popisa gledanja",
|
||||
"components.PermissionEdit.viewwatchlists": "Prikaži Plex popise gledanja",
|
||||
"components.PersonDetails.alsoknownas": "Poznat/a i kao: {names}",
|
||||
"components.PersonDetails.appearsin": "Nastupanja",
|
||||
"components.PersonDetails.ascharacter": "kao {character}",
|
||||
@@ -560,7 +560,7 @@
|
||||
"components.RequestButton.viewrequest": "Prikaz zahtjeva",
|
||||
"components.RequestButton.viewrequest4k": "Prikaz 4K zahtjeva",
|
||||
"components.RequestCard.approverequest": "Odobri zahtjev",
|
||||
"components.RequestCard.cancelrequest": "Prekini zahtjev",
|
||||
"components.RequestCard.cancelrequest": "Otkaži zahtjev",
|
||||
"components.RequestCard.declinerequest": "Odbij zahtjev",
|
||||
"components.RequestCard.deleterequest": "Izbriši zahtjev",
|
||||
"components.RequestCard.editrequest": "Uredi zahtjev",
|
||||
@@ -578,19 +578,19 @@
|
||||
"components.RequestModal.errorediting": "Dogodila se greška prilikom uređivanja zahtjeva.",
|
||||
"components.RequestModal.extras": "Dodaci",
|
||||
"components.RequestModal.numberofepisodes": "Broj epizoda",
|
||||
"components.RequestModal.pending4krequest": "4K zahtjeva na čekanju",
|
||||
"components.RequestModal.pending4krequest": "4K zahtjevi na čekanju",
|
||||
"components.RequestModal.pendingapproval": "Tvoj zahtjev čeka na odobrenje.",
|
||||
"components.RequestCard.tvdbid": "TVDB ID",
|
||||
"components.RequestModal.pendingrequest": "Zahtjevai na čekanju",
|
||||
"components.RequestModal.requestApproved": "Zahtjev za <strong>{title}</strong> je odobren!",
|
||||
"components.RequestModal.requestcancelled": "Zahtjev za <strong>{title}</strong> je prekinut.",
|
||||
"components.RequestModal.requestcollection4ktitle": "Zahtjev za zbirkom u 4K",
|
||||
"components.RequestModal.requestcollectiontitle": "Zahtjev za zbirkom",
|
||||
"components.RequestModal.requestcollection4ktitle": "Zatraži zbirku u 4K",
|
||||
"components.RequestModal.requestcollectiontitle": "Zatraži zbirku",
|
||||
"components.RequestModal.requesterror": "Dogodila se greška prilikom slanja zahtjeva.",
|
||||
"components.RequestModal.requestfrom": "Zahtjev korisnika {username} čeka na odobrenje.",
|
||||
"components.RequestModal.requestmovie4ktitle": "Zatraži film u 4K",
|
||||
"components.RequestModal.requestseries4ktitle": "Zatraži serije u 4K",
|
||||
"components.RequestModal.requestseriestitle": "Zatraži serije",
|
||||
"components.RequestModal.requestseries4ktitle": "Zatraži seriju u 4K",
|
||||
"components.RequestModal.requestseriestitle": "Zatraži seriju",
|
||||
"components.RequestModal.season": "Sezona",
|
||||
"components.RequestModal.seasonnumber": "Sezona {number}",
|
||||
"components.RequestModal.selectmovies": "Odaberi filmove",
|
||||
@@ -690,7 +690,7 @@
|
||||
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "Moraš odabrati najmanju dostupnost",
|
||||
"components.Settings.RadarrModal.validationPortRequired": "Moraš navesti valjani broj priključka",
|
||||
"components.Settings.RadarrModal.validationProfileRequired": "Moraš odabrati profil kvalitete",
|
||||
"components.Settings.SettingsAbout.Releases.currentversion": "Aktualno",
|
||||
"components.Settings.SettingsAbout.Releases.currentversion": "Trenutno",
|
||||
"components.Settings.SettingsAbout.Releases.latestversion": "Najnovije",
|
||||
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Podaci izdanja trenutačno nisu nedostupni.",
|
||||
"components.Settings.SettingsAbout.Releases.versionChangelog": "{version} – zapisnik promjena",
|
||||
@@ -718,7 +718,7 @@
|
||||
"components.StatusChecker.restartRequiredDescription": "Ponovo pokreni poslužitelja kako bi se ažurirane postavke primijenile.",
|
||||
"components.TvDetails.episodeRuntime": "Trajanje epizode",
|
||||
"components.TvDetails.nextAirDate": "Datum sljedećeg emitiranja",
|
||||
"components.TvDetails.rtaudiencescore": "Ocjena publike na Rotten Tomatoes",
|
||||
"components.TvDetails.rtaudiencescore": "Ocjena Rotten Tomatoes publike",
|
||||
"components.TvDetails.seasonnumber": "Sezona {seasonNumber}",
|
||||
"components.UserList.createlocaluser": "Stvori lokalnog korisnika",
|
||||
"components.UserList.deleteuser": "Izbriši korisnika",
|
||||
@@ -736,11 +736,11 @@
|
||||
"components.PermissionEdit.autorequestSeries": "Automatsko zahtijevanje serija",
|
||||
"components.PermissionEdit.createissues": "Prijavljivanje problema",
|
||||
"components.PermissionEdit.manageissues": "Upravljanje problemima",
|
||||
"components.PermissionEdit.managerequests": "Upravljanje zahtjevima",
|
||||
"components.PermissionEdit.managerequests": "Upravljaj zahtjevima",
|
||||
"components.PermissionEdit.request": "Zahtjev",
|
||||
"components.PermissionEdit.request4k": "Zahtjev za 4K",
|
||||
"components.PermissionEdit.request4kMovies": "Zahtjev za 4K filmove",
|
||||
"components.PermissionEdit.request4kTv": "Zahtjev za 4K serije",
|
||||
"components.PermissionEdit.request4k": "Zahtjev za 4K rezoluciju",
|
||||
"components.PermissionEdit.request4kMovies": "Zahtjev za filmove u 4K rezoluciji",
|
||||
"components.PermissionEdit.request4kTv": "Zahtjev za serije u 4K rezoluciji",
|
||||
"components.PermissionEdit.requestMovies": "Zahtjev za filmovima",
|
||||
"components.PersonDetails.birthdate": "Datum rođenja {birthdate}",
|
||||
"components.PersonDetails.crewmember": "Suradnik",
|
||||
@@ -827,7 +827,7 @@
|
||||
"components.Settings.Notifications.NotificationsWebhook.agentenabled": "Aktiviraj agenta",
|
||||
"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved": "Web push postavke obavijesti su uspješno spremljene!",
|
||||
"components.Settings.Notifications.NotificationsWebhook.authheader": "Zaglavlje autorizacije",
|
||||
"components.Settings.Notifications.NotificationsWebhook.resetPayload": "Vrati na zadane vrijednosti",
|
||||
"components.Settings.Notifications.NotificationsWebhook.resetPayload": "Resetiraj na zadane vrijednosti",
|
||||
"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed": "Neuspjelo slanje Webhook obavijesti provjere.",
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Neuspjelo spremanje Webhook postavki obavijesti.",
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved": "Webhook postavke obavijesti su uspješno spremljene!",
|
||||
@@ -938,7 +938,7 @@
|
||||
"components.TitleCard.cleardata": "Izbriši podatke",
|
||||
"components.TitleCard.mediaerror": "{mediaType} nije pronađen",
|
||||
"components.TitleCard.tmdbid": "TMDB ID",
|
||||
"components.TvDetails.Season.somethingwentwrong": "Dogodila se greška prilikom preuzimanja podataka sezona.",
|
||||
"components.TvDetails.Season.somethingwentwrong": "Dogodila se greška prilikom dohvaćanja podataka sezona.",
|
||||
"components.TvDetails.anime": "Anime",
|
||||
"components.TvDetails.episodeRuntimeMinutes": "{runtime} min",
|
||||
"components.TvDetails.firstAirDate": "Datum prvog emitiranja",
|
||||
@@ -948,12 +948,12 @@
|
||||
"components.TvDetails.originaltitle": "Izvorni naslov",
|
||||
"components.TvDetails.overview": "Pregled",
|
||||
"components.TvDetails.overviewunavailable": "Pregled nedostupan.",
|
||||
"components.TvDetails.play4konplex": "Reproduciraj u 4K na Plexu",
|
||||
"components.TvDetails.play4konplex": "Reproduciraj u 4K rezoluciji na Plexu",
|
||||
"components.TvDetails.playonplex": "Reproduciraj na Plexu",
|
||||
"components.TvDetails.productioncountries": "{countryCount, plural, one {zemlja produkcije} few {zemlje produkcije} other {zemalja produkcije}}",
|
||||
"components.TvDetails.recommendations": "Preporuke",
|
||||
"components.TvDetails.reportissue": "Prijavi problem",
|
||||
"components.TvDetails.rtcriticsscore": "Tomatometer na Rotten Tomatoes",
|
||||
"components.TvDetails.rtcriticsscore": "Rotten Tomatoes Tomatometar",
|
||||
"components.TvDetails.showtype": "Vrste serija",
|
||||
"components.TvDetails.similar": "Slične serije",
|
||||
"components.TvDetails.status4k": "4K {status}",
|
||||
@@ -983,7 +983,7 @@
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit": "Ograničenje zahtjeva za filmove",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.owner": "Vlasnik",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip": "Automatski zatraži serije na tvom <PlexWatchlistSupportLink>Plex popisu gledanja</PlexWatchlistSupportLink>",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Otkrij regiju",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Regionalno otkrivanje",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Dogodila se greška prilikom spremanja postavki.",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Postavke su uspješno spremljene!",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.user": "Korisnik",
|
||||
@@ -1042,7 +1042,7 @@
|
||||
"i18n.status": "Stanje",
|
||||
"pages.oops": "Ups",
|
||||
"components.Settings.advancedTooltip": "Neispravno konfiguriranje ove postavke može pokvariti funkcionalnost",
|
||||
"components.Settings.noDefaultNon4kServer": "Ako imate samo jedan {serverType} poslužitelj za ne-4K i za 4K sadržaj (ili ako preuzimaš samo 4K sadržaj), tvoj {serverType} poslužitelj <strong>NE </strong> bi trebao biti određen kao 4K poslužitelj.",
|
||||
"components.Settings.noDefaultNon4kServer": "Ako imaš samo jedan {serverType} poslužitelj za ne-4K i za 4K sadržaj (ili ako preuzimaš samo 4K sadržaj), <strong>NEMOJ</strong> odrediti svoj {serverType} poslužitelj kao 4K poslužitelj.",
|
||||
"components.PermissionEdit.requestMoviesDescription": "Dozvoli automatsko slanje zahtjeva za filmove koje nisu u 4K rezoluciji.",
|
||||
"components.PermissionEdit.autorequestDescription": "Dozvoli automatsko slanje zahtjeva za medije koji nisu u 4K rezoluciji putem Plex popisa gledanja.",
|
||||
"components.PermissionEdit.autorequestMoviesDescription": "Dozvoli automatsko slanje zahtjeva za filmove koji nisu u 4K rezoluciji putem Plex popisa gledanja.",
|
||||
@@ -1057,16 +1057,16 @@
|
||||
"components.PermissionEdit.request4kTvDescription": "Dozvoli slanje zahtjeva za serijama u 4K rezoluciji.",
|
||||
"components.PermissionEdit.usersDescription": "Dozvoli upravljanje korisnicima. Korisnici s ovom dozvolom ne mogu mijenjati korisnike s administratorskom privilegijom ili dozvoliti administratorske privilegije.",
|
||||
"components.PermissionEdit.viewissuesDescription": "Dozvoli prikaz problema s medijima koje su prijavili drugi korisnici.",
|
||||
"components.PermissionEdit.viewrequestsDescription": "Dozvoli prikaz medijskih zahtjeva koje su prijavili drugi korisnici.",
|
||||
"components.PermissionEdit.viewrequestsDescription": "Dozvoli prikaz zahtjeva za medije koje su poslali drugi korisnici.",
|
||||
"components.PermissionEdit.viewwatchlistsDescription": "Dozvoli prikaz Plex popisa gledanja drugih korisnika.",
|
||||
"components.Settings.notrunning": "Ne pokreće se",
|
||||
"components.Settings.serverRemote": "udaljeni",
|
||||
"components.RequestModal.QuotaDisplay.quotaLink": "Sažetak tvojih ograničenja zahtjeva možeš vidjeti na tvojoj <ProfileLink>stranici profila</ProfileLink>.",
|
||||
"components.RequestModal.QuotaDisplay.quotaLinkUser": "Sažetak ograničenja zahtjeva korisničkih zahtjeva možeš vidjeti na njihovoj <ProfileLink>stranici profila</ProfileLink>.",
|
||||
"components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Nema dovoljno preostalih zahtjeva za sezonama",
|
||||
"components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Nema dovoljno preostalih zahtjeva za sezone",
|
||||
"components.RequestModal.SearchByNameModal.nomatches": "Nismo uspjeli pronaći seriju koja odgovara ovoj seriji.",
|
||||
"components.RequestModal.SearchByNameModal.notvdbiddescription": "Nismo uspjeli automatski naći odgovarajuću seriju. Dolje odaberi odgovarajuću seriju.",
|
||||
"components.RequestModal.requestadmin": "Ovaj će se zahtjev automatski prihvatiti.",
|
||||
"components.RequestModal.requestadmin": "Ovaj će se zahtjev automatski odobriti.",
|
||||
"components.ResetPassword.emailresetlink": "E-mail poveznica za obnavljanje lozinke",
|
||||
"components.Settings.Notifications.NotificationsLunaSea.webhookUrlTip": "Tvoj korisničke ili na osnovi uređaja <LunaSeaLink>webhook URL obavijesti</LunaSeaLink>",
|
||||
"components.Settings.Notifications.NotificationsWebPush.httpsRequirement": "Za primanje web push obavijesti, Overseerr se mora posluživati putem HTTPS-a.",
|
||||
@@ -1080,7 +1080,7 @@
|
||||
"components.Settings.plexlibrariesDescription": "Biblioteke u kojima će Overseerr tražiti naslove. Postavi i spremi tvoje postavke Plex veze, a zatim pritisni gumb ispod ako je popis biblioteka prazan.",
|
||||
"components.Settings.startscan": "Pokreni pretraživanje",
|
||||
"components.Setup.scanbackground": "Pretraživanje se pokreće u pozadini. U međuvremenu možeš nastaviti s postupkom postavljanja.",
|
||||
"components.PermissionEdit.managerequestsDescription": "Dozvoli upravljanje zahtjevima za medijima. Svi zahtjevi korisnika s ovom dozvolom će se automatski odobriti.",
|
||||
"components.PermissionEdit.managerequestsDescription": "Dozvoli upravljanje zahtjevima za medije. Svi zahtjevi korisnika s ovom dozvolom će se automatski odobriti.",
|
||||
"components.Settings.Notifications.NotificationsWebhook.customJson": "JSON sadržaj",
|
||||
"components.Settings.SettingsJobsCache.plex-full-scan": "Pretraživanje cijele Plex biblioteke",
|
||||
"components.RequestModal.QuotaDisplay.allowedRequests": "Smiješ zatražiti <strong>{limit}</strong> {type} svakih <strong>{days}</strong> dana.",
|
||||
@@ -1094,12 +1094,149 @@
|
||||
"components.Settings.SettingsJobsCache.imagecache": "Predmemorija slika",
|
||||
"components.Settings.SettingsJobsCache.imagecachesize": "Ukupna veličina predmemorije",
|
||||
"components.Settings.SettingsJobsCache.imagecachecount": "Slike spremljene u predmemoriju",
|
||||
"components.Settings.SettingsJobsCache.imagecacheDescription": "Kad je u postavkama aktivirano, Overseerr će služiti kao posrednik i predmemorirati slike iz unaprijed konfiguriranih vanjskih izvora. Predmemorirane slike spremaju se u mapu konfiguracije. Datoteke možeš pronaći u <code>{appDataPath}/cache/images</code>.",
|
||||
"components.Settings.SettingsJobsCache.imagecacheDescription": "Kada je u postavkama aktivirano, Overseerr će služiti kao posrednik i predmemorirati slike iz unaprijed konfiguriranih vanjskih izvora. Predmemorirane slike spremaju se u mapu konfiguracije. Datoteke možeš pronaći u <code>{appDataPath}/cache/images</code>.",
|
||||
"components.DownloadBlock.formattedTitle": "{title}: Sezona {seasonNumber} Episoda {episodeNumber}",
|
||||
"components.RequestCard.unknowntitle": "Nepoznat naslov",
|
||||
"components.RequestList.RequestItem.unknowntitle": "Nepoznat naslov",
|
||||
"components.StatusBadge.seasonepisodenumber": "S{seasonNumber}E{episodeNumber}",
|
||||
"components.Discover.DiscoverTv.discovertv": "Serije",
|
||||
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Nedavno dodano",
|
||||
"components.Discover.DiscoverMovies.discovermovies": "Filmovi"
|
||||
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Nedavno dodani",
|
||||
"components.Discover.DiscoverMovies.discovermovies": "Filmovi",
|
||||
"components.Discover.moviegenres": "Žanrovi filmova",
|
||||
"components.Discover.FilterSlideover.keywords": "Ključne riječi",
|
||||
"components.Discover.FilterSlideover.activefilters": "{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}",
|
||||
"components.Discover.FilterSlideover.firstAirDate": "Datum prvog emitiranja",
|
||||
"components.Discover.PlexWatchlistSlider.plexwatchlist": "Tvoj Plex popis gledanja",
|
||||
"components.Discover.FilterSlideover.genres": "Žanrovi",
|
||||
"components.Discover.FilterSlideover.originalLanguage": "Izvorni jezik",
|
||||
"components.Discover.CreateSlider.editsuccess": "Uređen klizač i spremljene postavke prilagodbe otkrivanja.",
|
||||
"components.Discover.CreateSlider.slidernameplaceholder": "Naziv klizača",
|
||||
"components.Discover.DiscoverMovies.sortPopularityDesc": "Popularnost (silazno)",
|
||||
"components.Discover.CreateSlider.searchStudios": "Pretražite studije…",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Navdeite TMDB ID mreže",
|
||||
"components.Discover.CreateSlider.addfail": "Izrada novog klizača nije uspjela.",
|
||||
"components.Discover.DiscoverMovies.sortPopularityAsc": "Popularnost (uzlazno)",
|
||||
"components.Discover.CreateSlider.needresults": "Morate imati barem 1 rezultat.",
|
||||
"components.Discover.CreateSlider.addcustomslider": "Stvorite prilagođeni klizač",
|
||||
"components.Discover.CreateSlider.editSlider": "Uredi klizač",
|
||||
"components.Discover.CreateSlider.validationDatarequired": "Morate navesti vrijednost.",
|
||||
"components.Discover.CreateSlider.providetmdbstudio": "Navedite TMDB ID studija",
|
||||
"components.Discover.CreateSlider.searchGenres": "Traži žanrove…",
|
||||
"components.Discover.CreateSlider.editfail": "Uređivanje klizača nije uspjelo.",
|
||||
"components.Discover.CreateSlider.starttyping": "Počinje tipkati za pretraživanje.",
|
||||
"components.Discover.CreateSlider.addSlider": "Dodaj klizač",
|
||||
"components.Discover.CreateSlider.providetmdbsearch": "Navedite upit za pretraživanje",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "Navdeite TMDB ID ključne riječi",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "{keywordTitle} filmovi",
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "Morate navesti naslov.",
|
||||
"components.Discover.CreateSlider.nooptions": "Nema rezultata.",
|
||||
"components.Discover.CreateSlider.searchKeywords": "Pretraži ključne riječi…",
|
||||
"components.Discover.CreateSlider.addsuccess": "Stvoren je novi klizač i spremljene su postavke prilagodbe otkrivanja.",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "Navedite TMDB ID žanra",
|
||||
"components.Discover.DiscoverTv.sortTmdbRatingAsc": "TMDB ocjena (uzlazno)",
|
||||
"components.Discover.FilterSlideover.studio": "Studio",
|
||||
"components.Discover.FilterSlideover.ratingText": "Ocjena od {minValue} do {maxValue}",
|
||||
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "Prvo emitiranje (uzlazno)",
|
||||
"components.Discover.DiscoverTv.sortTmdbRatingDesc": "TMDB ocjena (silazno)",
|
||||
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "TMDB ocjena (uzlazno)",
|
||||
"components.Discover.FilterSlideover.clearfilters": "Obriši aktivne filtre",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "Datum izlaska (silazno)",
|
||||
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}",
|
||||
"components.Discover.FilterSlideover.streamingservices": "Streaming usluge",
|
||||
"components.Discover.FilterSlideover.tmdbuserscore": "TMDB ocjena korisnika",
|
||||
"components.Discover.DiscoverTv.sortPopularityAsc": "Popularnost (uzlazno)",
|
||||
"components.Discover.DiscoverTv.sortTitleAsc": "Naslov (A-Z) (uzlazno)",
|
||||
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "Prvo emitiranje (silazno)",
|
||||
"components.Discover.FilterSlideover.releaseDate": "Datum izlaska",
|
||||
"components.Discover.DiscoverSliderEdit.deletefail": "Greška pri uklanjanju klizača.",
|
||||
"components.Discover.FilterSlideover.runtime": "Trajanje",
|
||||
"components.Discover.FilterSlideover.from": "Od",
|
||||
"components.Discover.DiscoverMovies.sortTitleDesc": "Naslov (Z-A) (silazno)",
|
||||
"components.Discover.DiscoverTv.sortPopularityDesc": "Popularnost (silazno)",
|
||||
"components.Discover.FilterSlideover.to": "Do",
|
||||
"components.Discover.FilterSlideover.filters": "Filtri",
|
||||
"components.Discover.DiscoverSliderEdit.enable": "Vidljivost",
|
||||
"components.Discover.FilterSlideover.runtimeText": "trajanje {minValue}-{maxValue} minuta",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "Datum izlaska (uzlazno)",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "TMDB ocjena (silazno)",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "TMDB broj glasova korisnika",
|
||||
"components.Discover.DiscoverSliderEdit.deletesuccess": "Klizač uspješno uklonjen.",
|
||||
"components.Discover.DiscoverMovies.sortTitleAsc": "Naslov (A-Z) (uzlazno)",
|
||||
"components.Discover.DiscoverTv.sortTitleDesc": "Naslov (Z-A) (silazno)",
|
||||
"components.Discover.DiscoverSliderEdit.remove": "Ukloni",
|
||||
"components.Discover.tvgenres": "Žanrovi serija",
|
||||
"components.Discover.DiscoverTvKeyword.keywordSeries": "{keywordTitle} serije",
|
||||
"components.Selector.showmore": "Pokaži više",
|
||||
"components.Selector.searchGenres": "Odaberi žanrove …",
|
||||
"components.Selector.searchStudios": "Traži studija …",
|
||||
"components.Discover.tmdbtvgenre": "TMDB žanr serije",
|
||||
"components.Selector.showless": "Pokaži manje",
|
||||
"components.Selector.starttyping": "Počni tipkati za pretraživanje.",
|
||||
"components.Selector.searchKeywords": "Traži ključne riječi …",
|
||||
"components.Selector.nooptions": "Nema rezultata.",
|
||||
"components.Discover.tmdbmoviegenre": "TMDB žanr filmova",
|
||||
"components.Discover.FilterSlideover.voteCount": "Broj glasova između {minValue} i {maxValue}",
|
||||
"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds": "{jobScheduleHours, plural, one {Svake sekunde} few {Svake {jobScheduleHours} sekunde} other {Svakih {jobScheduleHours} sekundi}}",
|
||||
"components.Layout.Sidebar.browsemovies": "Filmovi",
|
||||
"components.Layout.Sidebar.browsetv": "Serije",
|
||||
"components.Discover.updatesuccess": "Aktualiziraj postavke za prilagođavanje otkrivanja.",
|
||||
"components.Discover.updatefailed": "Dogodila se greška tiijekom aktualiziranja postavki za prilagođavanje otkrivanja.",
|
||||
"components.Settings.SettingsMain.toastApiKeyFailure": "Dogodila se greška prilikom generiranja novog API ključa.",
|
||||
"components.Settings.SettingsMain.toastSettingsFailure": "Dogodila se greška prilikom spremanja postavki.",
|
||||
"components.Discover.PlexWatchlistSlider.emptywatchlist": "Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>Plex popis gledanja</PlexWatchlistSupportLink> pojavit će se ovdje.",
|
||||
"components.Discover.networks": "Mreže",
|
||||
"components.Discover.studios": "Studiji",
|
||||
"components.Settings.SettingsMain.hideAvailable": "Sakrij dostupne medije",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Zvuk obavijesti",
|
||||
"components.Discover.tmdbmoviekeyword": "TMDB ključna riječ filmova",
|
||||
"components.Discover.stopediting": "Prekini uređivanje",
|
||||
"components.Discover.resetsuccess": "Uspješno resetiranje postavki prilagodbe otkrivanja.",
|
||||
"components.Discover.customizediscover": "Prilagodi otkrivanje",
|
||||
"components.Settings.SettingsMain.locale": "Jezik prikaza",
|
||||
"components.Discover.tmdbtvkeyword": "TMDB ključna riječ serija",
|
||||
"components.Discover.tmdbnetwork": "TMDB mreža",
|
||||
"components.Settings.SettingsMain.applicationTitle": "Naslov programa",
|
||||
"components.Settings.SettingsMain.originallanguage": "Jezik otkrivanja",
|
||||
"components.Settings.SettingsMain.csrfProtection": "Aktiviraj CSRF zaštitu",
|
||||
"components.Discover.tmdbstudio": "TMDB studio",
|
||||
"components.Settings.SettingsMain.generalsettings": "Opće postavke",
|
||||
"components.MovieDetails.imdbuserscore": "IMDB ocjena korisnika",
|
||||
"components.Discover.tmdbtvstreamingservices": "TMDB streaming usluge za TV",
|
||||
"components.Settings.SettingsMain.apikey": "API ključ",
|
||||
"components.Settings.SettingsMain.cacheImages": "Aktiviraj predmemoriranje slika",
|
||||
"components.Discover.tmdbmoviestreamingservices": "TMDB streaming usluge filmova",
|
||||
"components.Discover.resetfailed": "Dogodila se greška prilikom resetiranja postavki prilagodbe otkrivanja.",
|
||||
"components.Discover.tmdbsearch": "TMDB pretraga",
|
||||
"components.Settings.SettingsMain.applicationurl": "URL programa",
|
||||
"components.Settings.SettingsMain.general": "Opće",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Zvuk obavijesti",
|
||||
"components.Discover.resettodefault": "Resetiraj na zadane vrijednosti",
|
||||
"components.Settings.SettingsMain.regionTip": "Filtriraj sadržaj prema regionalnoj dostupnosti",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Zadane postavke uređaja",
|
||||
"components.Settings.SettingsMain.region": "Regionalno otkrivanje",
|
||||
"components.Settings.SettingsMain.trustProxy": "Aktiviraj proxy podršku",
|
||||
"components.Settings.SettingsMain.toastSettingsSuccess": "Postavke su uspješno spremljene!",
|
||||
"i18n.collection": "Zbirka",
|
||||
"components.Settings.SettingsMain.originallanguageTip": "Filtriraj sadržaj po izvornom jeziku",
|
||||
"components.Settings.SettingsMain.cacheImagesTip": "Predmemoriraj slike eksternih izvora (zahtijeva značajnu količinu memorije na disku)",
|
||||
"components.Settings.SettingsJobsCache.availability-sync": "Sinkronizacija dostupnosti medija",
|
||||
"components.Settings.SettingsMain.trustProxyTip": "Dopusti Overseerru da ispravno registrira IP adrese klijenata iza proxyja",
|
||||
"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash": "URL ne smije završiti s kosom crtom",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Vrsta anime serije",
|
||||
"components.Settings.SettingsMain.generalsettingsDescription": "Konfiguriraj globalne i zadane postavke za Overseerr.",
|
||||
"components.Settings.SettingsMain.toastApiKeySuccess": "Novi API ključ je uspješno generiran!",
|
||||
"components.Settings.SonarrModal.seriesType": "Vrsta serije",
|
||||
"components.Settings.SettingsMain.csrfProtectionHoverTip": "NEMOJ aktivirati ovu postavku ako ne razumiješ što radiš!",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Zadane postavke uređaja",
|
||||
"components.Settings.SettingsMain.validationApplicationUrl": "Moraš navesti valjani URL",
|
||||
"components.Settings.SettingsMain.validationApplicationTitle": "Moraš navesti naslov programa",
|
||||
"components.Settings.SettingsMain.csrfProtectionTip": "Postavi eksterni API pristup u samo-za-čitanje (zahtijeva HTTPS)",
|
||||
"components.Discover.resetwarning": "Vrati sve klizače na zadane postavke. To će također izbrisati sve prilagođene klizače!",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Automatski dodaj dodatnu oznaku s korisničkim ID-om i prikaznim imenom podnositelja zahtjeva",
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Automatski dodaj dodatnu oznaku s korisničkim ID-om i prikaznim imenom podnositelja zahtjeva",
|
||||
"components.Discover.createnewslider": "Stvori novi klizač",
|
||||
"components.Settings.SettingsMain.partialRequestsEnabled": "Dopusti djelomične zahtjeve za seriju",
|
||||
"components.Settings.SonarrModal.tagRequests": "Označi zahtjeve",
|
||||
"components.Settings.RadarrModal.tagRequests": "Označi zahtjeve"
|
||||
}
|
||||
|
||||
@@ -426,7 +426,7 @@
|
||||
"components.Settings.SettingsJobsCache.jobname": "Feladat neve",
|
||||
"components.Settings.SettingsJobsCache.jobcancelled": "{jobname} törölve.",
|
||||
"components.Settings.SettingsJobsCache.flushcache": "Cache kiürítése",
|
||||
"components.Settings.SettingsJobsCache.download-sync-reset": "Szinkronizálás \"reset\" letöltése",
|
||||
"components.Settings.SettingsJobsCache.download-sync-reset": "Töltse le a Sync Reset",
|
||||
"components.Settings.SettingsJobsCache.download-sync": "Szinkronizálás letöltése",
|
||||
"components.Settings.SettingsJobsCache.command": "Parancs",
|
||||
"components.Settings.SettingsJobsCache.canceljob": "Feladat megszakítása",
|
||||
@@ -460,14 +460,14 @@
|
||||
"components.Settings.SettingsAbout.Releases.releases": "Kiadások",
|
||||
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Kiadási adatok nem állnak rendelkezésre.",
|
||||
"components.Settings.SettingsAbout.Releases.latestversion": "Legújabb",
|
||||
"components.Settings.SettingsAbout.Releases.currentversion": "Jelenlegi verzió",
|
||||
"components.Settings.SettingsAbout.Releases.currentversion": "Jelenlegi",
|
||||
"components.Settings.RadarrModal.validationRootFolderRequired": "Ki kell választania egy root mappát",
|
||||
"components.Settings.RadarrModal.validationProfileRequired": "Ki kell választania egy minőség profilt",
|
||||
"components.Settings.RadarrModal.validationPortRequired": "Érvényes portszámot kell megadnia",
|
||||
"components.Settings.RadarrModal.validationNameRequired": "Meg kell adnia a szerver nevét",
|
||||
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "Ki kell választania egy minimális elérhetőséget",
|
||||
"components.Settings.RadarrModal.validationHostnameRequired": "Meg kell adnia egy hostnevet vagy IP-címet",
|
||||
"components.Settings.RadarrModal.validationBaseUrlTrailingSlash": "Az alap URL-nek nem lehet vége perjel",
|
||||
"components.Settings.RadarrModal.validationHostnameRequired": "Érvényes gazdagépnevet vagy IP-címet kell megadnia",
|
||||
"components.Settings.RadarrModal.validationBaseUrlTrailingSlash": "Az URL alapja nem végződhet perjelre",
|
||||
"components.Settings.RadarrModal.validationBaseUrlLeadingSlash": "Az alap URL-nek perjellel kell végződnie",
|
||||
"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "Az URL-nek nem lehet vége perjel",
|
||||
"components.Settings.RadarrModal.validationApplicationUrl": "Érvényes URL-t kell megadnia",
|
||||
@@ -666,7 +666,7 @@
|
||||
"components.RequestList.RequestItem.requested": "Kérve",
|
||||
"components.RequestList.RequestItem.modifieduserdate": "{date} {user} által",
|
||||
"components.RequestList.RequestItem.modified": "Módosított",
|
||||
"components.RequestList.RequestItem.mediaerror": "A kéréshez társított címe már nem érhető el.",
|
||||
"components.RequestList.RequestItem.mediaerror": "{mediaType} Nem található",
|
||||
"components.RequestList.RequestItem.editrequest": "Kérés szerkesztése",
|
||||
"components.RequestList.RequestItem.deleterequest": "Kérés törlése",
|
||||
"components.RequestList.RequestItem.cancelRequest": "Kérés visszavonása",
|
||||
@@ -958,9 +958,9 @@
|
||||
"i18n.resolved": "Megoldva",
|
||||
"components.Settings.RadarrModal.inCinemas": "Mozikban",
|
||||
"components.Settings.SettingsJobsCache.editJobSchedule": "Feladat Módosítása",
|
||||
"components.Settings.SettingsJobsCache.editJobSchedulePrompt": "Gyakoriság",
|
||||
"components.Settings.SettingsJobsCache.editJobSchedulePrompt": "Új frekvencia",
|
||||
"components.RequestBlock.languageprofile": "Nyelv Profil",
|
||||
"components.RequestModal.requestApproved": "Kérés elfogadva: <strong>{title}</strong>",
|
||||
"components.RequestModal.requestApproved": "Kérés <strong>{title}</strong> elfogadva!",
|
||||
"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed": "A Gotify értesítési beállításait nem sikerült elmenteni.",
|
||||
"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess": "Gotify teszt értesítés elküldve!",
|
||||
"components.Settings.Notifications.NotificationsGotify.token": "Alkalmazás Token",
|
||||
@@ -1083,5 +1083,77 @@
|
||||
"components.RequestCard.tvdbid": "TheTVDB azonosító",
|
||||
"components.RequestList.RequestItem.tmdbid": "TMDB azonosító",
|
||||
"components.RequestList.RequestItem.tvdbid": "TheTVDB azonosító",
|
||||
"components.RequestModal.requestcollection4ktitle": "Gyűjtemény kérés 4K-ban"
|
||||
"components.RequestModal.requestcollection4ktitle": "Gyűjtemény kérés 4K-ban",
|
||||
"components.Discover.CreateSlider.editsuccess": "Szerkesztett csúszka és mentett felfedezés testreszabási beállítások.",
|
||||
"components.Settings.SettingsJobsCache.imagecache": "Képgyorsítótár",
|
||||
"components.Settings.SettingsJobsCache.imagecachesize": "Teljes gyorsítótár mérete",
|
||||
"components.Discover.CreateSlider.slidernameplaceholder": "Csúszka neve",
|
||||
"components.Discover.DiscoverTv.sortFirstAirDateAsc": "Első adás dátuma növekvő",
|
||||
"components.Discover.DiscoverMovies.sortPopularityDesc": "Népszerűség csökkenő",
|
||||
"components.Settings.SettingsJobsCache.image-cache-cleanup": "Képgyorsítótár tisztítása",
|
||||
"i18n.restartRequired": "Újraindítás szükséges",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingAsc": "TMDB minősítés növekvő",
|
||||
"components.Discover.FilterSlideover.clearfilters": "Aktív szűrők törlése",
|
||||
"components.Discover.CreateSlider.searchStudios": "Stúdiók keresése…",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateDesc": "Megjelenés dátuma csökkenő sorrendben",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Adja meg a TMDB hálózati azonosítót",
|
||||
"components.Settings.SettingsMain.applicationTitle": "Pályázat címe",
|
||||
"components.Discover.CreateSlider.addfail": "Nem sikerült új csúszkát létrehozni.",
|
||||
"components.Discover.DiscoverMovies.sortPopularityAsc": "Növekvő népszerűség",
|
||||
"components.Discover.CreateSlider.needresults": "Legalább 1 eredménynek kell lennie.",
|
||||
"components.Discover.CreateSlider.addcustomslider": "Egyéni csúszka létrehozása",
|
||||
"components.Discover.DiscoverTv.sortPopularityAsc": "Növekvő népszerűség",
|
||||
"components.Discover.CreateSlider.editSlider": "Csúszka szerkesztése",
|
||||
"components.Discover.CreateSlider.validationDatarequired": "Meg kell adnia egy adatértéket.",
|
||||
"components.Discover.DiscoverTv.sortFirstAirDateDesc": "Első adási dátum csökkenő",
|
||||
"components.Discover.DiscoverTv.discovertv": "Sorozat",
|
||||
"components.Discover.DiscoverSliderEdit.deletefail": "Nem sikerült törölni a csúszkát.",
|
||||
"components.Discover.CreateSlider.providetmdbstudio": "Adja meg a TMDB Studio azonosítóját",
|
||||
"components.Settings.SettingsMain.cacheImages": "Képgyorsítótár engedélyezése",
|
||||
"components.Discover.DiscoverTv.sortPopularityDesc": "Népszerűség csökkenő",
|
||||
"components.Discover.CreateSlider.searchGenres": "Műfajok keresése…",
|
||||
"components.Discover.CreateSlider.editfail": "Nem sikerült szerkeszteni a csúszkát.",
|
||||
"components.Discover.CreateSlider.starttyping": "Gépelés megkezdése a kereséshez.",
|
||||
"components.Discover.FilterSlideover.filters": "Szűrők",
|
||||
"components.Discover.DiscoverSliderEdit.enable": "Kapcsolja be a láthatóságot",
|
||||
"components.Discover.CreateSlider.addSlider": "Csúszka hozzáadása",
|
||||
"components.Settings.SettingsJobsCache.imagecachecount": "Képek gyorsítótárban",
|
||||
"components.Discover.CreateSlider.providetmdbsearch": "Adjon meg egy keresési lekérdezést",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "Adjon meg egy TMDB kulcsszóazonosítót",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "{keywordTitle} Filmek",
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "Meg kell adnia a címet.",
|
||||
"components.Discover.DiscoverMovies.sortReleaseDateAsc": "Kiadási dátum Növekvő sorrendben",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Értesítési hang",
|
||||
"components.Discover.CreateSlider.nooptions": "Nincs eredmény.",
|
||||
"components.Discover.CreateSlider.searchKeywords": "Kulcsszavak keresése…",
|
||||
"components.Discover.CreateSlider.addsuccess": "Új csúszkát hozott létre, és elmentette a felfedezés testreszabási beállításait.",
|
||||
"components.Discover.DiscoverSliderEdit.deletesuccess": "A csúszka sikeresen törölve.",
|
||||
"components.Discover.DiscoverMovies.discovermovies": "Filmek",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "Adjon meg egy TMDB műfajazonosítót",
|
||||
"components.Discover.DiscoverSliderEdit.remove": "Távolítsa el",
|
||||
"components.Discover.PlexWatchlistSlider.emptywatchlist": "A hozzáadott média a <PlexWatchlistSupportLink>Plex figyelőlistáján</PlexWatchlistSupportLink> elérhető.",
|
||||
"components.Discover.DiscoverTvKeyword.keywordSeries": "{keywordTitle} Sorzoat",
|
||||
"components.Discover.DiscoverMovies.sortTmdbRatingDesc": "TMDB Értékelés Csökkenő",
|
||||
"components.Discover.DiscoverTv.sortTitleAsc": "Cím (A-Z) Növekvő",
|
||||
"components.Discover.DiscoverTv.sortTitleDesc": "Cím (Z-A) Csökkenő",
|
||||
"components.Discover.FilterSlideover.ratingText": "Értékelések {minValue} és {maxValue} között",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "TMDB Felhasználók szavazat szám",
|
||||
"components.Discover.FilterSlideover.releaseDate": "Megjelenési dátum",
|
||||
"components.Discover.FilterSlideover.voteCount": "Értékelések száma {minValue} és {maxValue} között",
|
||||
"components.Discover.FilterSlideover.originalLanguage": "Eredeti Nyelv",
|
||||
"components.Discover.PlexWatchlistSlider.plexwatchlist": "A te Plex figyelőlistád",
|
||||
"components.Discover.RecentlyAddedSlider.recentlyAdded": "Nemrég hozzáadott",
|
||||
"components.Discover.moviegenres": "Film műfajok",
|
||||
"components.Discover.DiscoverMovies.sortTitleAsc": "Cím (A-Z) Növekvő",
|
||||
"components.Discover.DiscoverMovies.sortTitleDesc": "Cím (Z-A) Csökkenő",
|
||||
"components.Discover.DiscoverTv.sortTmdbRatingAsc": "TMDB Értékelés Növekvő",
|
||||
"components.Discover.DiscoverTv.sortTmdbRatingDesc": "TMDB Értékelés Csökkenő",
|
||||
"components.Discover.FilterSlideover.firstAirDate": "Első adási dátum",
|
||||
"components.Discover.FilterSlideover.genres": "Műfajok",
|
||||
"components.Discover.FilterSlideover.keywords": "Kulcsszavak",
|
||||
"components.Discover.FilterSlideover.runtime": "Músoridő",
|
||||
"components.Discover.FilterSlideover.runtimeText": "{minValue}-{maxValue} percnyi műsoridő",
|
||||
"components.Discover.FilterSlideover.studio": "Stúdió",
|
||||
"components.Discover.FilterSlideover.tmdbuserscore": "TMDB Felhasználói Értékelés",
|
||||
"components.Discover.FilterSlideover.streamingservices": "Streaming Szolgáltatók"
|
||||
}
|
||||
|
||||
@@ -1136,5 +1136,15 @@
|
||||
"components.Settings.SettingsMain.toastSettingsSuccess": "Impostazioni salvate con successo!",
|
||||
"components.UserProfile.plexwatchlist": "Plex Watchlist",
|
||||
"components.TvDetails.seasonstitle": "Stagioni",
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip": "Richiedi automaticamente le serie presenti nella tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>"
|
||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip": "Richiedi automaticamente le serie presenti nella tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>",
|
||||
"components.Discover.moviegenres": "Film per genere",
|
||||
"components.RequestModal.requestseries4ktitle": "Richiedi serie in 4K",
|
||||
"components.RequestModal.requestmovie4ktitle": "Richiedi film in 4K",
|
||||
"components.Discover.FilterSlideover.tmdbuserscore": "Voto utenti TMDB",
|
||||
"components.StatusBadge.openinarr": "Apri su {arr}",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Tipo serie anime",
|
||||
"components.Settings.SonarrModal.seriesType": "Tipo serie TV",
|
||||
"components.RequestModal.requestmovietitle": "Richiedi film",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "Numero voti utenti TMDB",
|
||||
"components.RequestModal.requestseriestitle": "Richiedi serie"
|
||||
}
|
||||
|
||||
@@ -1231,5 +1231,6 @@
|
||||
"components.Discover.DiscoverMovies.activefilters": "{count, plural, one {# 선택한 필터} other {# 선택한 필터}}",
|
||||
"components.QuotaSelector.seasons": "{count, plural, one {시즌} other {시즌}}",
|
||||
"components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {없음} other {<strong>#</strong>개의}} {type} {remaining, plural, one {요청} other {요청}} 남음",
|
||||
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "매 {jobScheduleHours, plural, one {시간} other {{jobScheduleHours} 시간}}"
|
||||
"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours": "매 {jobScheduleHours, plural, one {시간} other {{jobScheduleHours} 시간}}",
|
||||
"components.MovieDetails.imdbuserscore": "IMDB 사용자 점수"
|
||||
}
|
||||
|
||||
@@ -1224,5 +1224,19 @@
|
||||
"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.Discover.FilterSlideover.tmdbuservotecount": "Aantal stemmen TMDB-gebruikers",
|
||||
"components.Discover.FilterSlideover.voteCount": "Aantal stemmen tussen {minValue} en {maxValue}",
|
||||
"components.Settings.RadarrModal.tagRequests": "Tagverzoeken",
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Voeg automatisch een extra tag toe met de gebruikers-ID en weergavenaam van de aanvrager",
|
||||
"components.MovieDetails.imdbuserscore": "Gebruikersscore IMDB",
|
||||
"components.Settings.SonarrModal.tagRequests": "Tagverzoeken",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Voeg automatisch een extra tag toe met de gebruikers-ID en weergavenaam van de aanvrager",
|
||||
"i18n.collection": "Collectie",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Meldingsgeluid",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Apparaatstandaard",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Serietype anime",
|
||||
"components.Settings.SonarrModal.seriesType": "Serietype",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Meldingsgeluid",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Apparaatstandaard"
|
||||
}
|
||||
|
||||
@@ -1220,5 +1220,8 @@
|
||||
"components.Discover.updatefailed": "Wystąpił problem podczas aktualizowania ustawień odnajdywania.",
|
||||
"components.Settings.SettingsMain.apikey": "Klucz API",
|
||||
"components.Settings.SettingsMain.cacheImagesTip": "Pamięć podręczna dla obrazów pochodzących z zewnętrznych źródeł (wymaga znacznej ilości miejsca na dysku)",
|
||||
"components.Settings.SettingsMain.toastSettingsFailure": "Coś poszło nie tak podczas zapisywania ustawień."
|
||||
"components.Settings.SettingsMain.toastSettingsFailure": "Coś poszło nie tak podczas zapisywania ustawień.",
|
||||
"i18n.collection": "Kolekcja",
|
||||
"components.MovieDetails.imdbuserscore": "Ocena użytkowników IMDB",
|
||||
"components.Settings.SonarrModal.seriesType": "Typ serialu"
|
||||
}
|
||||
|
||||
@@ -1227,5 +1227,10 @@
|
||||
"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",
|
||||
"i18n.collection": "Coleção",
|
||||
"components.MovieDetails.imdbuserscore": "Pontuação de usuário IMDB",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Adiciona automaticamente uma tag adicional com o ID de usuário e nome de exibição de quem pediu",
|
||||
"components.Settings.SonarrModal.tagRequests": "Marcar Pedidos",
|
||||
"components.Settings.RadarrModal.tagRequests": "Marcar Pedidos"
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"components.PlexLoginButton.signinwithplex": "Conectat",
|
||||
"components.QuotaSelector.movieRequests": "{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>",
|
||||
"components.PersonDetails.lifespan": "{birthdate} – {deathdate}",
|
||||
"components.RequestBlock.seasons": "{seasonCount, plural, un {Season} alte {Seasons}}",
|
||||
"components.RequestBlock.seasons": "{seasonCount, plural, one {Sezon} other {Sezoane}}",
|
||||
"components.PermissionEdit.requestMoviesDescription": "Acordați permisiunea de a trimite solicitări pentru filme non-4K.",
|
||||
"components.PermissionEdit.viewissuesDescription": "Acordați permisiunea de a vizualiza problemele media raportate de alți utilizatori.",
|
||||
"components.PermissionEdit.viewwatchlistsDescription": "Acordați permisiunea de a vizualiza listele de urmărire Plex ale altor utilizatori.",
|
||||
@@ -403,8 +403,62 @@
|
||||
"components.RequestBlock.approve": "Aprobă Solicitarea",
|
||||
"components.RequestBlock.decline": "Respinge Solicitarea",
|
||||
"components.RequestBlock.requestedby": "Solicitat de",
|
||||
"components.RequestButton.approve4krequests": "Aprobă {requestCount, plural, o {4K Request} alte {{requestCount} 4K Requests}}",
|
||||
"components.RequestButton.approve4krequests": "Aprobă {requestCount, plural, one {Cerere 4K} other {{requestCount} Cereri 4K}}",
|
||||
"components.RequestBlock.lastmodifiedby": "Ultima Dată Modificat de",
|
||||
"components.RequestBlock.profilechanged": "Profil Calitate",
|
||||
"components.RequestBlock.requestdate": "Dată Solicitare"
|
||||
"components.RequestBlock.requestdate": "Dată Solicitare",
|
||||
"components.RequestButton.approverequests": "Aprobă {requestCount, plural, one {Cerere} other {{requestCount} Cereri}}",
|
||||
"components.RequestButton.requestmore4k": "Cere mai mult în 4K",
|
||||
"components.RequestButton.approverequest4k": "Aproba Cereri 4K",
|
||||
"components.RequestCard.tmdbid": "ID TMDB",
|
||||
"components.RequestCard.failedretry": "A apărut o eroare la reîncercarea solicitării.",
|
||||
"components.RequestButton.declinerequest": "Respinge Cerere",
|
||||
"components.RequestCard.seasons": "{seasonCount, plural, one {Sezon} other {Sezoane}}",
|
||||
"components.RequestCard.declinerequest": "Respinge Cererea",
|
||||
"components.RequestButton.viewrequest": "Vezi Cerere",
|
||||
"components.RequestButton.declinerequests": "Respinge {requestCount, plural, one {Cererea} other {{requestCount} Cererile}}",
|
||||
"components.RequestCard.mediaerror": "{mediaType} Nu a fost găsit",
|
||||
"components.RequestCard.editrequest": "Editează Cererea",
|
||||
"components.RequestButton.viewrequest4k": "Vezi Cerere 4K",
|
||||
"components.RequestButton.decline4krequests": "Respinge {requestCount, plural, one {Cererea 4K} other {{requestCount} Cererile 4K}}",
|
||||
"components.RequestButton.declinerequest4k": "Respinge Cerere 4K",
|
||||
"components.RequestCard.approverequest": "Aprobă Cererea",
|
||||
"components.RequestButton.approverequest": "Cereri Aprobate",
|
||||
"components.RequestCard.deleterequest": "Șterge Cererea",
|
||||
"components.RequestCard.unknowntitle": "Titlu necunoscut",
|
||||
"components.RequestList.RequestItem.cancelRequest": "Anulează Cerere",
|
||||
"components.RequestCard.tvdbid": "ID TheTVDB",
|
||||
"components.RequestButton.requestmore": "Cere mai mult",
|
||||
"components.RequestList.RequestItem.deleterequest": "Șterge Cerere",
|
||||
"components.RequestCard.cancelrequest": "Anulează Cererea",
|
||||
"components.RequestModal.AdvancedRequester.folder": "{path} ({space})",
|
||||
"components.RequestList.RequestItem.modified": "Modificat",
|
||||
"components.RequestList.RequestItem.editrequest": "Editează Cererea",
|
||||
"components.RequestModal.AdvancedRequester.qualityprofile": "Profil de Calitate",
|
||||
"components.RequestList.requests": "Cereri",
|
||||
"components.RequestModal.AdvancedRequester.advancedoptions": "Avansat",
|
||||
"components.RequestModal.AdvancedRequester.notagoptions": "Fără etichete.",
|
||||
"components.RequestList.RequestItem.modifieduserdate": "{date} de {user}",
|
||||
"components.RequestModal.AdvancedRequester.requestas": "Cere ca",
|
||||
"components.RequestList.showallrequests": "Afișează toate cererile",
|
||||
"components.RequestList.RequestItem.tmdbid": "ID-ul TMDB",
|
||||
"components.RequestList.RequestItem.requesteddate": "Solicitat",
|
||||
"components.RequestModal.QuotaDisplay.movie": "film",
|
||||
"components.RequestList.RequestItem.failedretry": "Ceva a mers greșit în timpul reîncercării cererii.",
|
||||
"components.RequestList.RequestItem.unknowntitle": "Titlu Necunoscut",
|
||||
"components.RequestModal.AdvancedRequester.destinationserver": "Server Destinație",
|
||||
"components.RequestModal.AdvancedRequester.rootfolder": "Folder Rădăcină",
|
||||
"components.RequestList.sortAdded": "Cele Mai Recente",
|
||||
"components.RequestModal.AdvancedRequester.tags": "Etichete",
|
||||
"components.RequestList.RequestItem.mediaerror": "{mediaType} nu a fost găsit",
|
||||
"components.RequestList.sortModified": "Ultima Modificată",
|
||||
"components.RequestList.RequestItem.tvdbid": "ID-ul TheTVDB",
|
||||
"components.RequestModal.AdvancedRequester.selecttags": "Selectați Etichetele",
|
||||
"components.RequestList.RequestItem.requested": "Solicitat",
|
||||
"components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Nu sunt suficiente cereri de sezon rămase",
|
||||
"components.RequestModal.AdvancedRequester.default": "{name} (Implicit)",
|
||||
"components.RequestModal.AdvancedRequester.languageprofile": "Profil de Limbă",
|
||||
"components.RequestModal.QuotaDisplay.allowedRequestsUser": "Acest utilizator are voie sa ceara <strong>{limit}</strong> {type} la fiecare <strong>{days}</strong> zile.",
|
||||
"components.RequestList.RequestItem.seasons": "",
|
||||
"components.RequestModal.QuotaDisplay.allowedRequests": "Aveți voie să cereți <strong>{limit}</strong> de {type} la fiecare <strong>{days}</strong> zile."
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
"pages.oops": "Упс",
|
||||
"pages.returnHome": "Вернуться домой",
|
||||
"components.CollectionDetails.overview": "Обзор",
|
||||
"components.CollectionDetails.numberofmovies": "{count} фильмов",
|
||||
"components.CollectionDetails.numberofmovies": "{count} {count, plural, one {фильм} few {фильма} other {фильмов}}",
|
||||
"components.CollectionDetails.requestcollection": "Запросить Коллекцию",
|
||||
"components.Login.email": "Адрес электронной почты",
|
||||
"components.UserList.users": "Пользователи",
|
||||
@@ -983,7 +983,7 @@
|
||||
"components.Discover.CreateSlider.addcustomslider": "Создать слайдер",
|
||||
"components.Discover.CreateSlider.nooptions": "Нет результатов.",
|
||||
"components.Discover.CreateSlider.providetmdbgenreid": "Введите TMDB ID жанра",
|
||||
"components.Discover.CreateSlider.needresults": "Должен быть хотя-бы 1 результат.",
|
||||
"components.Discover.CreateSlider.needresults": "Должен быть хотя бы 1 результат.",
|
||||
"components.Discover.CreateSlider.providetmdbkeywordid": "Введите TMDB ID ключевого слова",
|
||||
"components.Discover.CreateSlider.providetmdbnetwork": "Введите TMDB ID сети",
|
||||
"components.Discover.CreateSlider.providetmdbsearch": "Введите поисковой запрос",
|
||||
@@ -992,7 +992,7 @@
|
||||
"components.Discover.CreateSlider.searchKeywords": "Поиск ключевых слов…",
|
||||
"components.Discover.CreateSlider.searchStudios": "Поиск студий…",
|
||||
"components.Discover.CreateSlider.slidernameplaceholder": "Название слайдера",
|
||||
"components.Discover.CreateSlider.starttyping": "Начините писать для поиска.",
|
||||
"components.Discover.CreateSlider.starttyping": "Начните писать для поиска.",
|
||||
"components.Discover.CreateSlider.validationDatarequired": "Вы должны ввести дату.",
|
||||
"components.Discover.CreateSlider.validationTitlerequired": "Вы должны ввести заголовок.",
|
||||
"components.Discover.DiscoverMovieKeyword.keywordMovies": "Фильмы по ключевому слову \"{keywordTitle}\"",
|
||||
@@ -1024,7 +1024,7 @@
|
||||
"components.Discover.DiscoverSliderEdit.deletesuccess": "Слайдер успешно удален.",
|
||||
"components.Discover.DiscoverSliderEdit.enable": "Изменить видимость",
|
||||
"components.Discover.DiscoverSliderEdit.remove": "Удалить",
|
||||
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {# Активный фильтр} other {# Активные фильтры}}",
|
||||
"components.Discover.DiscoverTv.activefilters": "{count, plural, one {# Активен фильтр} other {# Активные фильтры }}",
|
||||
"components.Discover.DiscoverTv.discovertv": "Сериалы",
|
||||
"components.Discover.DiscoverTv.sortPopularityAsc": "Популярность по возрастанию",
|
||||
"components.Discover.DiscoverTv.sortPopularityDesc": "Популярность по убыванию",
|
||||
@@ -1221,5 +1221,22 @@
|
||||
"components.Selector.showless": "Показать меньше",
|
||||
"components.Selector.showmore": "Показать больше",
|
||||
"components.Settings.SettingsJobsCache.imagecachesize": "Размер кэша",
|
||||
"components.Settings.validationUrlBaseLeadingSlash": "Базовый URL должен начинаться с косой черты"
|
||||
"components.Settings.validationUrlBaseLeadingSlash": "Базовый URL должен начинаться с косой черты",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "Количество голосов пользователей TMDB",
|
||||
"components.Discover.FilterSlideover.voteCount": "Количество голосов между {minValue} и {maxValue}",
|
||||
"components.Discover.tmdbmoviestreamingservices": "Стриминговые сервисы фильмов TMDB",
|
||||
"components.Discover.tmdbtvstreamingservices": "Стриминговые сервисы сериалов TMDB",
|
||||
"components.Settings.RadarrModal.tagRequestsInfo": "Автоматически добавлять дополнительный тег с ID и именем запросившего пользователя",
|
||||
"components.Settings.RadarrModal.tagRequests": "Теги запросов",
|
||||
"components.MovieDetails.imdbuserscore": "Оценка пользователей IMDB",
|
||||
"components.Settings.SettingsJobsCache.availability-sync": "Синхронизация доступности медиа",
|
||||
"components.Settings.SonarrModal.tagRequests": "Теги запросов",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "Автоматически добавлять тег с ID и именем запросившего пользователя",
|
||||
"i18n.collection": "Коллекция",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "Звук уведомления",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Устройство по умолчанию",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "Тип аниме-сериала",
|
||||
"components.Settings.SonarrModal.seriesType": "Тип сериала",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Звук уведомления",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Устройство по умолчанию"
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhookUrl": "Webhook adresa",
|
||||
"components.ManageSlideOver.manageModalAdvanced": "Napredno",
|
||||
"components.ManageSlideOver.manageModalMedia": "Mediji",
|
||||
"components.Settings.Notifications.NotificationsWebhook.customJson": "JSON Payload",
|
||||
"components.Settings.Notifications.NotificationsWebhook.customJson": "JSON zadržaj",
|
||||
"components.Settings.SettingsLogs.label": "Labela",
|
||||
"components.Settings.SettingsLogs.level": "Ozbiljnost",
|
||||
"components.Settings.SettingsAbout.Releases.versionChangelog": "{version} Dnevnik promena",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1242
src/i18n/locale/uk.json
Normal file
1242
src/i18n/locale/uk.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -281,7 +281,7 @@
|
||||
"components.CollectionDetails.requestcollection": "提交系列请求",
|
||||
"components.CollectionDetails.overview": "简介",
|
||||
"components.CollectionDetails.numberofmovies": "{count} 部电影",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "必须使用链接挂载(bind mount)指定某个宿主机器的文件夹跟容器内的 <code>{appDataPath}</code> 文件夹连通,才能保存 Overseerr 的配置和数据。",
|
||||
"components.AppDataWarning.dockerVolumeMissingDescription": "卷(<code>{appDataPath}</code>)挂载配置不正确,当容器终止或重启时所有数据都会被清除。",
|
||||
"components.PersonDetails.ascharacter": "饰演 {character}",
|
||||
"pages.somethingwentwrong": "出了点问题",
|
||||
"pages.serviceunavailable": "服务器无法使用",
|
||||
@@ -1174,7 +1174,7 @@
|
||||
"components.Discover.PlexWatchlistSlider.emptywatchlist": "您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink>中的媒体会显示在这里。",
|
||||
"components.Selector.starttyping": "开始打字以进行搜索。",
|
||||
"components.Discover.CreateSlider.starttyping": "开始打字以进行搜索。",
|
||||
"components.Discover.CreateSlider.needresults": "你需要至少有 1 个结果。",
|
||||
"components.Discover.CreateSlider.needresults": "需要至少有 1 个结果。",
|
||||
"components.Selector.showless": "显示更少",
|
||||
"components.Discover.resetfailed": "重置探索媒体设置时出了点问题。",
|
||||
"components.Settings.SettingsMain.validationApplicationTitle": "你必须提供一个应用程序标题",
|
||||
@@ -1231,5 +1231,12 @@
|
||||
"components.Settings.SonarrModal.tagRequests": "标记请求",
|
||||
"i18n.collection": "合集",
|
||||
"components.Discover.FilterSlideover.tmdbuservotecount": "TMDB 用户评分数",
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "自动添加带有请求者的用户 ID 和显示名称的附加标签"
|
||||
"components.Settings.SonarrModal.tagRequestsInfo": "自动添加带有请求者的用户 ID 和显示名称的附加标签",
|
||||
"components.MovieDetails.imdbuserscore": "IMDB 用户评分",
|
||||
"components.Settings.Notifications.NotificationsPushover.sound": "通知提示音",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "默认设备",
|
||||
"components.Settings.SonarrModal.animeSeriesType": "动漫剧集类型",
|
||||
"components.Settings.SonarrModal.seriesType": "剧集类型",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "通知提示音",
|
||||
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "默认设备"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
|
||||
switch (locale) {
|
||||
case 'ar':
|
||||
return import('../i18n/locale/ar.json');
|
||||
case 'bg':
|
||||
return import('../i18n/locale/bg.json');
|
||||
case 'ca':
|
||||
return import('../i18n/locale/ca.json');
|
||||
case 'cs':
|
||||
@@ -40,8 +42,14 @@ const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
|
||||
return import('../i18n/locale/el.json');
|
||||
case 'es':
|
||||
return import('../i18n/locale/es.json');
|
||||
case 'fi':
|
||||
return import('../i18n/locale/fi.json');
|
||||
case 'fr':
|
||||
return import('../i18n/locale/fr.json');
|
||||
case 'he':
|
||||
return import('../i18n/locale/he.json');
|
||||
case 'hi':
|
||||
return import('../i18n/locale/hi.json');
|
||||
case 'hr':
|
||||
return import('../i18n/locale/hr.json');
|
||||
case 'hu':
|
||||
@@ -64,6 +72,8 @@ const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
|
||||
return import('../i18n/locale/pt_BR.json');
|
||||
case 'pt-PT':
|
||||
return import('../i18n/locale/pt_PT.json');
|
||||
case 'ro':
|
||||
return import('../i18n/locale/ro.json');
|
||||
case 'ru':
|
||||
return import('../i18n/locale/ru.json');
|
||||
case 'sq':
|
||||
@@ -72,6 +82,8 @@ const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
|
||||
return import('../i18n/locale/sr.json');
|
||||
case 'sv':
|
||||
return import('../i18n/locale/sv.json');
|
||||
case 'uk':
|
||||
return import('../i18n/locale/uk.json');
|
||||
case 'zh-CN':
|
||||
return import('../i18n/locale/zh_Hans.json');
|
||||
case 'zh-TW':
|
||||
|
||||
@@ -11205,10 +11205,10 @@ prettier-plugin-tailwindcss@0.2.3:
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.3.tgz#b68a1de10056fc84055426af132c2697bea0955c"
|
||||
integrity sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ==
|
||||
|
||||
prettier@2.8.4:
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
|
||||
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
|
||||
prettier@3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
|
||||
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
|
||||
|
||||
pretty-bytes@^5.6.0:
|
||||
version "5.6.0"
|
||||
|
||||
Reference in New Issue
Block a user