diff --git a/.all-contributorsrc b/.all-contributorsrc index 5b8d00db..c0f24e34 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -431,6 +431,33 @@ "contributions": [ "translation" ] + }, + { + "login": "acortelyou", + "name": "Alex Cortelyou", + "avatar_url": "https://avatars.githubusercontent.com/u/1689668?v=4", + "profile": "https://github.com/acortelyou", + "contributions": [ + "code" + ] + }, + { + "login": "jonocairns", + "name": "Jono Cairns", + "avatar_url": "https://avatars.githubusercontent.com/u/182836?v=4", + "profile": "https://nz.linkedin.com/in/jonocairns", + "contributions": [ + "code" + ] + }, + { + "login": "DJScias", + "name": "DJScias", + "avatar_url": "https://avatars.githubusercontent.com/u/439655?v=4", + "profile": "https://scias.net/", + "contributions": [ + "translation" + ] } ], "badgeTemplate": "\"All-orange.svg\"/>", diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..fcadb2cf --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 751a8c07..489e4aaa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: run: yarn build build_and_push: - name: Build & Publish to Docker Hub + name: Build & Publish Docker Images needs: test if: github.ref == 'refs/heads/develop' && !contains(github.event.head_commit.message, '[skip ci]') runs-on: ubuntu-20.04 @@ -38,23 +38,23 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Cache Docker layers - uses: actions/cache@v2.1.4 + uses: actions/cache@v2.1.5 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} restore-keys: | ${{ runner.os }}-buildx- - - name: Login to DockerHub + - name: Log in to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} - - name: Login to GitHub Container Registry + - name: Log in to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} - password: ${{ secrets.CR_PAT }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ddccdd1..62b2ecb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Setup Node.js + - name: Set up Node.js uses: actions/setup-node@v2 with: node-version: 14 @@ -38,17 +38,17 @@ jobs: uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - name: Login to DockerHub + - name: Log in to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} - - name: Login to GitHub Container Registry + - name: Log in to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} - password: ${{ secrets.CR_PAT }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Install dependencies run: yarn - name: Release diff --git a/.github/workflows/snap.yaml b/.github/workflows/snap.yaml index 9fd27835..ea7f92f9 100644 --- a/.github/workflows/snap.yaml +++ b/.github/workflows/snap.yaml @@ -2,7 +2,8 @@ name: Publish Snap on: push: - branches: [develop] + branches: + - develop jobs: jobs: @@ -11,14 +12,15 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.8.0 + uses: styfle/cancel-workflow-action@0.9.0 with: access_token: ${{ secrets.GITHUB_TOKEN }} + test: name: Lint & Test Build needs: jobs runs-on: ubuntu-20.04 - container: node:12.18-alpine + container: node:14.16-alpine steps: - name: checkout uses: actions/checkout@v2 @@ -30,6 +32,7 @@ jobs: run: yarn lint - name: build run: yarn build + build-snap: name: Build Snap Package (${{ matrix.architecture }}) needs: test @@ -44,7 +47,6 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v2 - - name: Prepare id: prepare run: | @@ -54,35 +56,31 @@ jobs: else echo ::set-output name=RELEASE::edge fi - - name: Set Up QEMU uses: docker/setup-qemu-action@v1 with: image: tonistiigi/binfmt@sha256:df15403e06a03c2f461c1f7938b171fda34a5849eb63a70e2a2109ed5a778bde - - name: Build Snap Package uses: diddlesnaps/snapcraft-multiarch-action@v1 id: build with: architecture: ${{ matrix.architecture }} - - name: Upload Snap Package uses: actions/upload-artifact@v2 with: name: overseerr-snap-package-${{ matrix.architecture }} path: ${{ steps.build.outputs.snap }} - - name: Review Snap Package uses: diddlesnaps/snapcraft-review-tools-action@v1.2.0 with: snap: ${{ steps.build.outputs.snap }} - - name: Publish Snap Package uses: snapcore/action-publish@v1 with: store_login: ${{ secrets.SNAP_LOGIN }} snap: ${{ steps.build.outputs.snap }} release: ${{ steps.prepare.outputs.RELEASE }} + discord: name: Send Discord Notification needs: build-snap @@ -91,7 +89,6 @@ jobs: steps: - name: Get Build Job Status uses: technote-space/workflow-conclusion-action@v2.1.5 - - name: Combine Job Status id: status run: | @@ -101,7 +98,6 @@ jobs: else echo ::set-output name=status::$WORKFLOW_CONCLUSION fi - - name: Post Status to Discord uses: sarisia/actions-status-discord@v1 with: diff --git a/README.md b/README.md index 07a836c6..2fa70358 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Language grade: JavaScript GitHub -All Contributors +All Contributors

@@ -22,18 +22,14 @@ - Full Plex integration. Authenticate and manage user access with Plex! - Easy integration with your existing services. Currently, Overseerr supports Sonarr and Radarr. More to come! -- Plex library sync, to keep track of the titles which are already available. +- Plex library scan, to keep track of the titles which are already available. - Customizable request system, which allows users to request individual seasons or movies in a friendly, easy-to-use interface. - Incredibly simple request management UI. Don't dig through the app to simply approve recent requests! - Granular permission system. - Support for various notification agents. - Mobile-friendly design, for when you need to approve requests on the go! -## Planned Features - -- Additional notification types. -- Issues system. This will allow users to report issues with content on your media server. -- And a ton more! Check out our [issue tracker](https://github.com/sct/overseerr/issues) to see the features which have already been requested. +With more features on the way! Check out our [issue tracker](https://github.com/sct/overseerr/issues) to see the features which have already been requested. ## Getting Started @@ -41,27 +37,6 @@ Check out our documentation for instructions on how to install and run Overseerr https://docs.overseerr.dev/getting-started/installation -## Running Overseerr - -Currently, Overseerr is primarily distributed as Docker images. If you have Docker installed, you can simply run Overseerr with: - -``` -docker run -d \ - --name overseerr \ - -e LOG_LEVEL=info \ - -e TZ=Asia/Tokyo \ - -p 5055:5055 \ - -v /path/to/appdata/config:/app/config \ - --restart unless-stopped \ - sctx/overseerr -``` - -After running Overseerr for the first time, configure it by visiting the web UI at http://[address]:5055 and completing the setup steps - -For more information and alternative installation methods, please see the [Overseerr documentation](https://docs.overseerr.dev/getting-started/installation). - -⚠️ Overseerr is currently under very heavy, rapid development and things are likely to break often. We need all the help we can get to find bugs and get them fixed to hit a more stable release. If you would like to help test the bleeding edge, please use the `sctx/overseerr:develop` image instead! ⚠️ - ## Preview @@ -158,6 +133,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Torkil

🌍
Jagandeep Brar

📖
dtalens

🌍 +
Alex Cortelyou

💻 +
Jono Cairns

💻 +
DJScias

🌍 diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 0e84bdeb..36afc905 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -9,10 +9,15 @@ ## Using Overseerr - [Settings](using-overseerr/settings/README.md) +- [Users](using-overseerr/users/README.md) - [Notifications](using-overseerr/notifications/README.md) - [Email](using-overseerr/notifications/email.md) - [Discord](using-overseerr/notifications/discord.md) - - [Webhooks](using-overseerr/notifications/webhooks.md) + - [Pushbullet](using-overseerr/notifications/pushbullet.md) + - [Pushover](using-overseerr/notifications/pushover.md) + - [Slack](using-overseerr/notifications/slack.md) + - [Telegram](using-overseerr/notifications/telegram.md) + - [Webhook](using-overseerr/notifications/webhooks.md) ## Support diff --git a/docs/extending-overseerr/reverse-proxy-examples.md b/docs/extending-overseerr/reverse-proxy-examples.md index 659feb88..2a06d9f4 100644 --- a/docs/extending-overseerr/reverse-proxy-examples.md +++ b/docs/extending-overseerr/reverse-proxy-examples.md @@ -1,14 +1,20 @@ # Reverse Proxy Examples {% hint style="warning" %} -Base URLs cannot be configured in Overseerr. With this limitation, only subdomain configurations are supported. However, a Nginx subfolder workaround configuration is provided below to use at your own risk. +Base URLs cannot be configured in Overseerr. With this limitation, only subdomain configurations are supported. + +A Nginx subfolder workaround configuration is provided below, but it is not officially supported. {% endhint %} ## SWAG -A sample proxy configuration is included in [SWAG (Secure Web Application Gateway)](https://github.com/linuxserver/docker-swag). However, this page is still the only source of truth, so the SWAG sample configuration is not guaranteed to be up-to-date. If you find an inconsistency, please [report it to the LinuxServer team](https://github.com/linuxserver/reverse-proxy-confs/issues/new) or [submit a pull request to update it](https://github.com/linuxserver/reverse-proxy-confs/pulls). +A sample proxy configuration is included in [SWAG (Secure Web Application Gateway)](https://github.com/linuxserver/docker-swag). -To use the bundled configuration file, simply rename `overseerr.subdomain.conf.sample` in the `proxy-confs` folder to `overseerr.subdomain.conf`. Alternatively, create a new file `overseerr.subdomain.conf` in `proxy-confs` with the following configuration: +However, this page is still the only source of truth, so the SWAG sample configuration is not guaranteed to be up-to-date. If you find an inconsistency, please [report it to the LinuxServer team](https://github.com/linuxserver/reverse-proxy-confs/issues/new) or [submit a pull request to update it](https://github.com/linuxserver/reverse-proxy-confs/pulls). + +To use the bundled configuration file, simply rename `overseerr.subdomain.conf.sample` in the `proxy-confs` folder to `overseerr.subdomain.conf`. + +Alternatively, you can create a new file `overseerr.subdomain.conf` in `proxy-confs` with the following configuration: ```nginx server { @@ -22,20 +28,18 @@ server { client_max_body_size 0; location / { - include /config/nginx/proxy.conf; resolver 127.0.0.11 valid=30s; set $upstream_app overseerr; set $upstream_port 5055; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; - } } ``` -## Traefik \(v2\) +## Traefik (v2) Add the following labels to the Overseerr service in your `docker-compose.yml` file: @@ -51,7 +55,7 @@ labels: - "traefik.http.services.overseerr-svc.loadbalancer.server.port=5055" ``` -For more information, see the Traefik documentation for a [basic example](https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/). +For more information, please refer to the [Traefik documentation](https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/). ## Nginx @@ -84,24 +88,6 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Ssl on; - real_ip_header CF-Connecting-IP; - # Control the behavior of the Referer header (Referrer-Policy) - add_header Referrer-Policy "no-referrer"; - # HTTP Strict Transport Security - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; - # Reduce XSS risks (Content-Security-Policy) - uncomment to use and add URLs whenever necessary - # add_header Content-Security-Policy "default-src 'self'; connect-src 'self' https://plex.tv; style-src 'self' 'unsafe-inline' https://rsms.me/inter/inter.css; script-src 'self' 'unsafe-inline'; img-src 'self' data: https://plex.tv https://assets.plex.tv https://gravatar.com https://secure.gravatar.com https://i2.wp.com https://image.tmdb.org; font-src 'self' https://rsms.me/inter/font-files/" always; - # Prevent some categories of XSS attacks (X-XSS-Protection) - add_header X-XSS-Protection "1; mode=block" always; - # Provide clickjacking protection (X-Frame-Options) - add_header X-Frame-Options "SAMEORIGIN" always; - # Prevent Sniff Mimetype (X-Content-Type-Options) - add_header X-Content-Type-Options "nosniff" always; - # Tell crawling bots to not index the site - add_header X-Robots-Tag "noindex, nofollow" always; - - access_log /var/log/nginx/overseerr.example.com-access.log; - error_log /var/log/nginx/overseerr.example.com-error.log; location / { proxy_pass http://127.0.0.1:5055; @@ -114,12 +100,15 @@ Then, create a symlink to `/etc/nginx/sites-enabled`: ```bash sudo ln -s /etc/nginx/sites-available/overseerr.example.com.conf /etc/nginx/sites-enabled/overseerr.example.com.conf ``` + {% endtab %} {% tab title="Subfolder" %} {% hint style="warning" %} -Nginx subfolder reverse proxy is unsupported. The sub filters may stop working when Overseerr is updated. Use at your own risk! +This Nginx subfolder reverse proxy is an unsupported workaround, and only provided as an example. The filters may stop working when Overseerr is updated. + +If you encounter any issues with Overseerr while using this workaround, we may ask you to try to reproduce the problem without the Nginx proxy. {% endhint %} Add the following location block to your existing `nginx.conf` file. @@ -127,13 +116,16 @@ Add the following location block to your existing `nginx.conf` file. ```nginx location ^~ /overseerr { set $app 'overseerr'; + # Remove /overseerr path to pass to the app rewrite ^/overseerr/?(.*)$ /$1 break; - proxy_pass http://127.0.0.1:5055; # NO TRAILING SLASH + proxy_pass http://127.0.0.1:5055; # NO TRAILING SLASH + # Redirect location headers proxy_redirect ^ /$app; proxy_redirect /setup /$app/setup; proxy_redirect /login /$app/login; + # Sub filters to replace hardcoded paths proxy_set_header Accept-Encoding ""; sub_filter_once off; @@ -152,6 +144,7 @@ location ^~ /overseerr { sub_filter '/site.webmanifest' '/$app/site.webmanifest'; } ``` + {% endtab %} {% endtabs %} diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 88e213fd..55f8a5f0 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,7 +1,7 @@ # Installation {% hint style="danger" %} -Overseerr is currently under very heavy, rapid development and things are likely to break often. We need all the help we can get to find bugs and get them fixed to hit a more stable release. If you would like to help test the bleeding edge, please use the image **`sctx/overseerr:develop`** instead! +Overseerr is currently in beta. If you would like to help test the bleeding edge, please use the image **`sctx/overseerr:develop`**! {% endhint %} {% hint style="info" %} @@ -32,7 +32,7 @@ docker run -d \ ```yaml --- -version: "3" +version: '3' services: overseerr: @@ -68,7 +68,7 @@ docker run -d \ {% tab title="Manual Update" %} -```text +```bash # Stop the Overseerr container docker stop overseerr @@ -116,7 +116,7 @@ Docker on Windows works differently than it does on Linux; it uses a VM to run a ## Linux {% hint style="info" %} -The [Overseerr snap](https://snapcraft.io/overseerr) is the only supported linux install method. Currently, the listening port cannot be changed. Port `5055` will need to be available on your host. To install snapd please refer to [Installing snapd](https://snapcraft.io/docs/installing-snapd). +The [Overseerr snap](https://snapcraft.io/overseerr) is the only officially supported Linux install method aside from [Docker](#docker). Currently, the listening port cannot be changed, so port `5055` will need to be available on your host. To install `snapd`, please refer to the [Snapcraft documentation](https://snapcraft.io/docs/installing-snapd). {% endhint %} **To install:** @@ -142,7 +142,7 @@ sudo snap install overseerr --edge This version can break any moment. Be prepared to troubleshoot any issues that arise! {% endhint %} -## Third Party +## Third-Party {% tabs %} diff --git a/docs/support/asking-for-support.md b/docs/support/asking-for-support.md index 2743827e..ad696926 100644 --- a/docs/support/asking-for-support.md +++ b/docs/support/asking-for-support.md @@ -1,33 +1,40 @@ # Asking for Support -## Before Asking for Support +Before seeking help, please make sure you have first tried these following: -Before seeking help, please make sure you have tried these following first: +- **Updating** Overseerr to the latest version. +- **Stopping and restarting** Overseerr. +- **Restarting** your machine. +- **Clearing** your browser cache. +- **Analyzing** your logs, you just might find the solution yourself! +- **Searching** the [documentation](../), [installation guide](../getting-started/installation.md), and [FAQs](./faq.md). -- **Update** to the latest version. -- ["Have you tried turning it off and on again?"](https://www.youtube.com/watch?v=nn2FB1P_Mn8) -- **Analyze** your logs, you just might find the solution yourself! -- **Search** the [Wiki](../), [Installation Guides](../getting-started/installation.md), and [FAQs](faq.md). -- If you have questions, feel free to ask on [Discord](https://discord.gg/PkCWJSeCk7) \(Please review our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_CONDUCT.md).\) Be sure to include a link to your logs. See [How can I share my logs?](asking-for-support.md#how-can-i-share-my-logs) below. +If you still have questions after troubleshooting on your own, feel free to ask on [Discord](https://discord.gg/PkCWJSeCk7)! (Please review our [Code of Conduct](https://github.com/sct/overseerr/blob/develop/CODE_OF_CONDUCT.md) before posting.) + +Be sure to also include a link to your logs. (Please see [How can I share my logs?](asking-for-support.md#how-can-i-share-my-logs) below.) ## What should I include when asking for support? -When you contact support, a vague statement like "it doesn't work" leaves little to go on to figure out what is wrong for you. When contacting support, try to include as much information as possible. Try to answer the following questions: +When contacting support, please try to include as much information as possible. A vague statement like "it doesn't work" provides very little to go on, and makes it difficult for us to help you. -- What did you try to do? When you describe what you did to reach the state you are in, we may notice something you did differently from the official instructions, or something required by your unique setup. The following are questions that should be answered in your request: +Try to answer the following questions: + +- What were you trying to do, and how did you attempt it? - What command did you enter? - What did you click on? - What settings did you change? + - Did you follow official instructions, or a third-party guide? - Provide a step-by-step list of what you tried. -- What do you see? We cannot see your screen so some of the following is necessary for us to know what is going on: + - Provide a brief description of your setup. +- What exactly do you see? - Did something happen? - Did something not happen? - Are there any error messages showing? - Provide screenshots to help us see what you are seeing. - - Share your Overseerr logs, which show exactly what happened and are often critical for identifying issues \(see [How can I share my logs?](asking-for-support.md#how-can-i-share-my-logs) below\). + - Share your Overseerr logs, which show exactly what happened and are often critical for identifying issues (see [How can I share my logs?](asking-for-support.md#how-can-i-share-my-logs) below). ## How can I share my logs? -1. Locate the log file at `/logs/overseerr.log` +1. Locate the current log file at `/logs/overseerr.log`. 2. Open the log file and **copy its contents** into a [**secret gist** on GitHub](https://gist.github.com/). If you upload your logs elsewhere, we may ask you to share them again via GitHub Gist. 3. **Share the link/URL to your secret gist** in the [`#support` channel in our Discord server](https://discord.gg/PkCWJSeCk7). diff --git a/docs/support/faq.md b/docs/support/faq.md index b80b7751..b74bf918 100644 --- a/docs/support/faq.md +++ b/docs/support/faq.md @@ -1,46 +1,54 @@ # Frequently Asked Questions (FAQ) {% hint style="info" %} -If you can't find a solution here, please ask on [Discord](https://discord.gg/PkCWJSeCk7). Please do not post questions on the GitHub issues tracker. +If you can't find the solution to your problem here, please seek help on [Discord](https://discord.gg/PkCWJSeCk7). + +_Please do not post questions or support requests on the GitHub issue tracker!_ {% endhint %} ## General -### I receive 409 or 400 errors when requesting a movie or TV series! - -**A:** Verify you are running Radarr and Sonarr v3. Overseerr was developed for v3 and is not currently backwards-compatible with previous versions. - ### How do I keep Overseerr up-to-date? -**A:** Use a 3rd party updating mechanism such as [Watchtower](https://github.com/containrrr/watchtower) or [Ouroboros](https://github.com/pyouroboros/ouroboros) to keep Overseerr up-to-date automatically. +Use a third-party update mechanism (such as [Watchtower](https://github.com/containrrr/watchtower), [Ouroboros](https://github.com/pyouroboros/ouroboros), or [Pullio](https://hotio.dev/pullio)) to keep Overseerr up-to-date automatically. -### How can I access Overseerr outside my home network? +### How can I access Overseerr outside of my home network? -**A:** The easy and least secure method is to forward an external port \(`5055`\) on your router to the internal port used by Overseerr \(default is TCP `5055`\). Visit [Port Forward](http://portforward.com/) for instructions for your particular router. You will then be able to access Overseerr via `http://EXTERNAL-IP-ADDRESS:5055`. +The easiest but least secure method is to simply forward an external port (e.g., `5055`) on your router to the internal port used by Overseerr (default is TCP `5055`). Visit [Port Forward](http://portforward.com/) for instructions for your particular router. You would then be able to access Overseerr via `http://EXTERNAL-IP-ADDRESS:5055`. -The more advanced and most preferred method \(and more secure if you use SSL\) is to set up a web server with NGINX/Apache, and use a reverse proxy to access Overseerr. You can lookup many guides on the internet to find out how to do this. There are several reverse proxy config examples located [here](../extending-overseerr/reverse-proxy-examples.md). +A more advanced, user-friendly, and secure (if using SSL) method is to set up a web server and use a reverse proxy to access Overseerr. Please refer to our [reverse proxy examples](../extending-overseerr/reverse-proxy-examples.md) for more information. -The most secure method, but also the most inconvenient, is to set up a VPN tunnel to your home server, then you can access Overseerr as if it is on a local network via `http://LOCAL-IP-ADDRESS:5055`. +The most secure method (but also the most inconvenient method) is to set up a VPN tunnel to your home server. You would then be able to access Overseerr as if you were on your local network, via `http://LOCAL-IP-ADDRESS:5055`. ### Overseerr is amazing! But it is not translated in my language yet! Can I help with translations? -**A:** You sure can! We are using [Weblate](https://hosted.weblate.org/engage/overseerr/) for translations. If your language is not listed, please [open a feature request on GitHub](https://github.com/sct/overseerr/issues/new/choose). +You sure can! We are using [Weblate](https://hosted.weblate.org/engage/overseerr/) for translations. If your language is not listed, please [open a feature request on GitHub](https://github.com/sct/overseerr/issues/new/choose). ### Where can I find the changelog? -**A:** You can find the changelog in the **Settings → About** page in your Overseerr instance. You can also find it on [GitHub](https://github.com/sct/overseerr/releases). +You can find the changelog in the **Settings → About** page in your Overseerr instance if you are using the `latest` tag. You can alternatively review the [release/version history on GitHub](https://github.com/sct/overseerr/releases). -### Can I make 4K requests? - -**A:** Yes! When adding your 4K Sonarr/Radarr server in **Settings → Services**, tick the `4K Server` checkbox. You also need to tick the `Default Server` checkbox if it is the default server you would like to use for 4K content requests. (To enable 4K requests, there need to be default Sonarr/Radarr servers for both 4K content **and** non-4K content.) +If you are using the `develop` tag, please refer to the [commit history for that branch on GitHub](https://github.com/sct/overseerr/commits/develop). ### Some media is missing from Overseerr that I know is in Plex! -**A:** Overseerr supports the new Plex Movie, legacy Plex Movie, TheTVDB, and TMDb agents. Please verify that your library is using one of the agents previously listed. If you are changing agents, a full metadata refresh will need to be performed. Caution, this can take a long time depending on how many items you have in your movie library. +Overseerr currently supports the following agents: -**Troubleshooting Steps:** +- New Plex Movie +- Legacy Plex Movie +- New Plex TV +- Legacy Plex TV +- TheTVDB +- TMDb +- [HAMA](https://github.com/ZeroQI/Hama.bundle) -First, check the Overseerr logs for media items that are missing. The logs will contain an error as to why that item could not be matched. One example might be `errorMessage":"SQLITE_CONSTRAINT: NOT NULL`. This means that the TMDb ID is missing from the Plex XML for that item. +Please verify that your library is using one of the agents previously listed. + +When changing agents, a full metadata refresh of your Plex library is required. (Caution: This can take a long time depending on the size of your library.) + +#### Troubleshooting Steps + +First, check the Overseerr logs for media items that are missing. The logs will contain an error as to why that item could not be matched. 1. Verify that you are using one of the agents mentioned above. 2. Refresh the metadata for just that item. @@ -58,44 +66,56 @@ You can also perform the following to verify the media item has a GUID Overseerr 3. TheTVDB agent `guid="com.plexapp.agents.thetvdb://78874/1/1"` 4. Legacy Plex Movie agent `guid="com.plexapp.agents.imdb://tt0765446"` -### TV series requests are failing after I updated Overseerr! +### Where can I find the log files? -**A:** Language profile support for Sonarr was added in [#860](https://github.com/sct/overseerr/pull/860), along with a new "Language Profile" required setting. If your TV series requests are failing, please make sure that you have a default language profile configured for each of your Sonarr servers in **Settings → Services**. +Please see [these instructions on how to locate and share your logs](./asking-for-support#how-can-i-share-my-logs). -### Where can I find the logs? +## Users -**A:** The logs are located at `/logs/overseerr.log` +### Why can't I see all of my Plex users? -## User management - -### Why can't I see all my Plex users? - -**A:** Navigate to your **User List** in Overseerr and click **Import Users from Plex** button. Don't forget to check the default user permissions in the **Settings → General Settings** page beforehand. +Please see the [documentation for importing users from Plex](../using-overseerr/users#importing-users-from-plex). ### Can I create local users in Overseerr? -**A:** Head to the **Users** page and hit **Create Local User**. Keep in mind that local user accounts need a valid email address. +Yes! Please see the [documentation for creating local users](../using-overseerr/users#creating-local-users). ### Is is possible to set user roles in Overseerr? -**A:** User roles can be set for each user on the **Users** page. The list of assignable permissions is one that is still growing, so if you have any suggestions, [make a feature request](https://github.com/sct/overseerr/issues/new/choose) on GitHub. +Permissions can be configured for each user via the **User List** or their **User Settings** page. The list of assignable permissions is still growing, so if you have any suggestions, [submit a feature request](https://github.com/sct/overseerr/issues/new/choose)! ## Requests +### I receive 409 or 400 errors when requesting a movie or TV series! + +Verify you are running v3 of both Radarr and Sonarr. Overseerr is not backwards-compatible with previous versions. + +### Can I allow users to submit 4K requests? + +Yes! If you keep both non-4K and 4K content in your media libraries, you can link separate 4K Radarr/Sonarr servers to allow users to submit 4K requests. (You must configure default non-4K **and** default 4K Radarr/Sonarr servers.) + +Please see the [Services documentation](../using-overseerr/settings/README.md#services) for details on how to configure your Radarr and/or Sonarr servers. + +Note that users must also have the **Request 4K**, **Request 4K Movies**, and/or **Request 4K Series** permissions in order to submit requests for 4K content. + ### I approved a requested movie and Radarr didn't search for it! -**A:** Check the minimum availability setting in your Radarr server. If a movie does not meet the minimum availability requirement, no search will be performed. Also verify that Radarr did not perform a search, by checking the Radarr logs. Lastly, verify that the item was not already being monitored by Radarr prior to approving the request. +Check the minimum availability setting in your Radarr server. If a movie does not meet the minimum availability requirement, no search will be performed. Also verify that Radarr did not perform a search, by checking the Radarr logs. Lastly, verify that the item was not already being monitored by Radarr prior to approving the request. ### Help! My request still shows "requested" even though it is in Plex! -**A:** See "[Some media is missing from Overseerr that I know is in Plex!](./faq.md#some-media-is-missing-from-overseerr-that-i-know-is-in-plex)" for troubleshooting steps. +See "[Some media is missing from Overseerr that I know is in Plex!](./faq.md#some-media-is-missing-from-overseerr-that-i-know-is-in-plex)" for troubleshooting steps. -### Approved series requests keep failing! +### Series requests keep failing! -**A:** If you configured a base URL in Sonarr, make sure you have set the base URL option appropriately in Overseerr. Also, check that you are using Sonarr v3 and have configured a default language profile in Overseerr. +If you configured a base URL in Sonarr, make sure you have set the base URL option appropriately in Overseerr. + +Also, check that you are using Sonarr v3 and that you have configured a default language profile in Overseerr. + +Language profile support for Sonarr was added in [#860](https://github.com/sct/overseerr/pull/860), along with a new, _required_ **Language Profile** setting. If series requests are failing, make sure that you have a default language profile configured for each of your Sonarr servers in **Settings → Services**. ## Notifications ### I am getting "Username and Password not accepted" when attempting to send email notifications via Gmail! -**A:** If you have 2-Step Verification enabled on your account, you will need to create an [app password](https://support.google.com/mail/answer/185833). +If you have 2-Step Verification enabled on your account, you will need to create an [app password](https://support.google.com/mail/answer/185833). diff --git a/docs/using-overseerr/notifications/README.md b/docs/using-overseerr/notifications/README.md index 05005233..5836e089 100644 --- a/docs/using-overseerr/notifications/README.md +++ b/docs/using-overseerr/notifications/README.md @@ -1,15 +1,15 @@ # Notifications -Overseerr already supports a good number of notification agents, such as **Discord**, **Slack** and **Pushover**. New agents are always considered for development, if there is enough demand for it. - ## Supported Notification Agents +Overseerr currently supports the following notification agents: + - [Email](./email.md) - [Discord](./discord.md) -- Pushbullet -- Pushover -- Slack -- Telegram +- [Pushbullet](./pushbullet.md) +- [Pushover](./pushover.md) +- [Slack](./slack.md) +- [Telegram](./telegram.md) - [Webhooks](./webhooks.md) ## Setting Up Notifications @@ -22,4 +22,4 @@ Note that some notifications are intended for the user who submitted the relevan ## Requesting New Notification Agents -If we do not currently support a notification agent you would like, feel free to request it on [GitHub](https://github.com/sct/overseerr/issues). However, please be sure to search first and confirm that there is not already an existing request for the agent! +If we do not currently support your preferred notification agent, feel free to [submit a feature request on GitHub](https://github.com/sct/overseerr/issues). However, please be sure to search first and confirm that there is not already an existing request for the agent! diff --git a/docs/using-overseerr/notifications/discord.md b/docs/using-overseerr/notifications/discord.md index a546ba38..f46b93ac 100644 --- a/docs/using-overseerr/notifications/discord.md +++ b/docs/using-overseerr/notifications/discord.md @@ -1,11 +1,25 @@ # Discord +{% hint style="info" %} +The following notification types will mention _all_ users with the **Manage Requests** permission, as these notification types are intended for application administrators rather than end users: + +- Media Requested +- Media Automatically Approved +- Media Failed + +On the other hand, the notification types below will only mention the user who submitted the request: + +- Media Approved (does not include automatic approvals) +- Media Declined +- Media Available + +In order for users to be mentioned in Discord notifications, they must have their [Discord user ID](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-) configured and **Enable Mentions** checked in their Discord notification user settings. +{% endhint %} + ## Configuration {% hint style="info" %} -In order to configure Discord notifications, you first need to [create a webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks). - -In order for users to be mentioned in Discord notifications, they must have their [Discord user ID](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-) configured in their user settings. +To configure Discord notifications, you first need to [create a webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks). {% endhint %} ### Bot Username (optional) diff --git a/docs/using-overseerr/notifications/email.md b/docs/using-overseerr/notifications/email.md index fd2c71c0..1cd5839a 100644 --- a/docs/using-overseerr/notifications/email.md +++ b/docs/using-overseerr/notifications/email.md @@ -9,15 +9,16 @@ The following email notification types are sent to _all_ users with the **Manage On the other hand, the email notification types below are only sent to the user who submitted the request: -- Media Approved +- Media Approved (does not include automatic approvals) - Media Declined - Media Available +In order for users to receive email notifications, they must have **Enable Notifications** checked in their email notification user settings. {% endhint %} ## Configuration -### Sender Address (required) +### Sender Address Set this to the email address you would like to appear in the "from" field of the email message. @@ -51,4 +52,6 @@ Configure these values as appropriate to authenticate with your SMTP host. ### PGP Private Key & Password (optional) -Configure these values to enable encrypting and signing of email messages using [OpenPGP](https://www.openpgp.org/). Note that individual users must also have their PGP public keys enabled in their user settings in order for PGP encryption to be used. +Configure these values to enable encrypting and signing of email messages using [OpenPGP](https://www.openpgp.org/). Note that individual users must also have their **PGP public keys** configured in their user settings in order for PGP encryption to be used in messages addressed to them. + +When configuring the PGP keys, be sure to keep the entire contents of the key intact. For example, private keys always begin with `-----BEGIN PGP PRIVATE KEY BLOCK-----` and end with `-----END PGP PRIVATE KEY BLOCK-----`. diff --git a/docs/using-overseerr/notifications/pushbullet.md b/docs/using-overseerr/notifications/pushbullet.md new file mode 100644 index 00000000..45edcc3a --- /dev/null +++ b/docs/using-overseerr/notifications/pushbullet.md @@ -0,0 +1,7 @@ +# Pushbullet + +## Configuration + +### Access Token + +[Create an access token](https://www.pushbullet.com/#settings) and set it here to grant Overseerr access to the Pushbullet API. diff --git a/docs/using-overseerr/notifications/pushover.md b/docs/using-overseerr/notifications/pushover.md new file mode 100644 index 00000000..55893dba --- /dev/null +++ b/docs/using-overseerr/notifications/pushover.md @@ -0,0 +1,15 @@ +# Pushover + +## Configuration + +### Application/API Token + +[Register an application](https://pushover.net/apps/build) and enter the API token in this field. (You can use one of the [official icons in our GitHub repository](https://github.com/sct/overseerr/tree/develop/public) when configuring the application.) + +For more details on registering applications or the API token, please see the [Pushover API documentation](https://pushover.net/api#registration). + +### User Key + +Set this to the user key for your Pushover account. Alternatively, you can set this to a group key to deliver notifications to multiple users. + +For more details, please see the [Pushover API documentation](https://pushover.net/api#identifiers). diff --git a/docs/using-overseerr/notifications/slack.md b/docs/using-overseerr/notifications/slack.md new file mode 100644 index 00000000..5b9d0fd7 --- /dev/null +++ b/docs/using-overseerr/notifications/slack.md @@ -0,0 +1,7 @@ +# Slack + +## Configuration + +### Webhook URL + +Simply [create a webhook](https://catflixserver.slack.com/apps/new/A0F7XDUAZ-incoming-webhooks) and enter the URL in this field. diff --git a/docs/using-overseerr/notifications/telegram.md b/docs/using-overseerr/notifications/telegram.md new file mode 100644 index 00000000..ddbd992e --- /dev/null +++ b/docs/using-overseerr/notifications/telegram.md @@ -0,0 +1,38 @@ +# Telegram + +{% hint style="info" %} +All notification types will be sent to the chat ID configured in your Overseerr application settings. + +If a user has configured a chat ID and has **Enable Notifications** checked in their Telegram notification user settings as well, they will be sent the following notification types for requests which they submit: + +- Media Approved (does not include automatic approvals) +- Media Declined +- Media Available + +{% endhint %} + +## Configuration + +{% hint style="info" %} +In order to configure Telegram notifications, you first need to [create a bot](https://telegram.me/BotFather). + +Bots **cannot** initiate conversations with users, users must have your bot added to a conversation in order to receive notifications. +{% endhint %} + +### Bot Username (optional) + +If this value is configured, users will be able to start a chat with your bot and configure their own personal notifications. + +The bot username should end with `_bot`, and the `@` prefix should be omitted. + +### Bot Authentication Token + +At the end of the bot creation process, [@BotFather](https://telegram.me/botfather) will provide an authentication token. + +### Chat ID + +To obtain your chat ID, simply create a new group chat, add [@get_id_bot](https://telegram.me/get_id_bot), and issue the `/my_id` command. + +### Send Silently (optional) + +Instagram allows you to enable silent notifications. Those will present a pop-up to the user, but will not make any sound. That's a per user configuration. diff --git a/docs/using-overseerr/notifications/webhooks.md b/docs/using-overseerr/notifications/webhooks.md index d1e91284..3717c2e4 100644 --- a/docs/using-overseerr/notifications/webhooks.md +++ b/docs/using-overseerr/notifications/webhooks.md @@ -1,10 +1,10 @@ -# Webhooks +# Webhook -Webhooks allow you to send a custom JSON payload to any endpoint. You can also set an authorization header for security purposes. +The webhook notification agent allows you to send a custom JSON payload to any endpoint. ## Configuration -### Webhook URL (required) +### Webhook URL The URL you would like to post notifications to. Your JSON will be sent as the body of the request. @@ -16,7 +16,7 @@ This is typically not needed. Please refer to your webhook provider's documentat This value will be sent as an `Authorization` HTTP header. -### JSON Payload (required) +### JSON Payload Customize the JSON payload to suit your needs. Overseerr provides several [template variables](./webhooks.md#template-variables) for use in the payload, which will be replaced with the relevant data when the notifications are triggered. @@ -31,24 +31,29 @@ Customize the JSON payload to suit your needs. Overseerr provides several [templ ### User -These variables are usually the target user of the notification. +These variables are for the target recipient of the notification. - `{{notifyuser_username}}` Target user's username. -- `{{notifyuser_email}}` Target user's email. -- `{{notifyuser_avatar}}` Target user's avatar. -- `{{notifyuser_settings_discordId}}` Target user's discord ID (if one is set). -- `{{notifyuser_settings_telegramChatId}}` Target user's telegram Chat ID (if one is set). +- `{{notifyuser_email}}` Target user's email address. +- `{{notifyuser_avatar}}` Target user's avatar URL. +- `{{notifyuser_settings_discordId}}` Target user's Discord ID (if one is set). +- `{{notifyuser_settings_telegramChatId}}` Target user's Telegram Chat ID (if one is set). -### Media +{% hint style="info" %} +The `notifyuser` variables are not set for the following notification types, as they are intended for application administrators rather than end users: -These variables are only included in media related notifications, such as requests. +- Media Requested +- Media Automatically Approved +- Media Failed -- `{{media_type}}` Media type. Either `movie` or `tv`. -- `{{media_tmdbid}}` Media's TMDb ID. -- `{{media_imdbid}}` Media's IMDb ID. -- `{{media_tvdbid}}` Media's TVDB ID. -- `{{media_status}}` Media's availability status (e.g., `AVAILABLE` or `PENDING`). -- `{{media_status4k}}` Media's 4K availability status (e.g., `AVAILABLE` or `PENDING`). +On the other hand, the `notifyuser` variables _will_ be replaced with the requesting user's information for the below notification types: + +- Media Approved +- Media Declined +- Media Available + +If you would like to use the requesting user's information in your webhook, please instead include the relevant variables from the [Request](#request) section below. +{% endhint %} ### Special @@ -57,3 +62,25 @@ The following variables must be used as a key in the JSON payload (e.g., `"{{ext - `{{request}}` This object will be `null` if there is no relevant request object for the notification. - `{{media}}` This object will be `null` if there is no relevant media object for the notification. - `{{extra}}` This object will contain the "extra" array of additional data for certain notifications. + +#### Media + +These `{{media}}` special variables are only included in media-related notifications, such as requests. + +- `{{media_type}}` Media type. Either `movie` or `tv`. +- `{{media_tmdbid}}` Media's TMDb ID. +- `{{media_imdbid}}` Media's IMDb ID. +- `{{media_tvdbid}}` Media's TVDB ID. +- `{{media_status}}` Media's availability status (e.g., `AVAILABLE` or `PENDING`). +- `{{media_status4k}}` Media's 4K availability status (e.g., `AVAILABLE` or `PENDING`). + +#### Request + +The `{{request}}` special variables are only included in request-related notifications. + +- `{{request_id}}` Request ID. +- `{{requestedBy_username}}` Requesting user's username. +- `{{requestedBy_email}}` Requesting user's email address. +- `{{requestedBy_avatar}}` Requesting user's avatar URL. +- `{{requestedBy_settings_discordId}}` Requesting user's Discord ID (if one is set). +- `{{requestedBy_settings_telegramChatId}}` Requesting user's Telegram Chat ID (if one is set). diff --git a/docs/using-overseerr/settings/README.md b/docs/using-overseerr/settings/README.md index 9b4c5a2e..1753c944 100644 --- a/docs/using-overseerr/settings/README.md +++ b/docs/using-overseerr/settings/README.md @@ -38,18 +38,6 @@ If you enable this setting and find yourself unable to access Overseerr, you can This setting is **disabled** by default. -### Enable Image Caching - -{% hint style="danger" %} -**This feature is experimental.** Enable it at your own risk! -{% endhint %} - -When enabled, all images (including media posters from TMDb) will be cached locally on your server. Images will also be optimized for client devices; i.e., if you access Overseerr using a mobile device, smaller versions will be served compared to when accessing Overseerr on desktop. - -Note that this feature requires and will use a significant amount of disk space, and there is currently no automated deletion of old or expired images. If running Overseerr using Docker, it is possible to manually clear the image cache by simply removing and recreating the container. - -This setting is **disabled** by default. - ### Discover Region & Discover Language These settings filter content shown on the "Discover" home page based on regional availability and original language, respectively. Users can override these global settings by configuring these same options in their user settings. @@ -78,9 +66,21 @@ When disabled, Plex OAuth becomes the only sign-in option, and any "local users" This setting is **enabled** by default. +### Global Movie Request Limit & Global Series Request Limit + +Select the request limits you would like granted to users. + +Unless an [override](../users/README.md#movie-request-limit-and-series-request-limit) is configured, users are granted these global request limits. + +Note that users with the **Manage Users** permission are exempt from request limits, since that permission also grants the ability to submit requests on behalf of other users. + ### Default User Permissions -Select the permissions you would like new users to have by default. It is important to set these, as any user with access to your Plex server will be able to log in to Overseerr, and they will be granted the permissions you select here. +Select the permissions you would like assigned to new users to have by default upon account creation. + +It is important to configure this, as any user with access to your Plex server will be able to sign in to Overseerr, and they will be granted the permissions you select here upon first sign-in. + +This setting only affects new users, and has no impact on existing users. In order to modify permissions for existing users, you will need to [edit the users](../users/README.md#editing-users). ## Plex diff --git a/docs/using-overseerr/users/README.md b/docs/using-overseerr/users/README.md new file mode 100644 index 00000000..bff049ba --- /dev/null +++ b/docs/using-overseerr/users/README.md @@ -0,0 +1,75 @@ +# Users + +## Owner Account + +The user account created during Overseerr setup is the "Owner" account, which cannot be deleted or modified by other users. This account's credentials are used to authenticate with Plex. + +## Adding Users + +There are currently two methods to add users to Overseerr: importing Plex users and creating "local users." All new users are created with the [default permissions](../settings/README.md#default-user-permissions) defined in **Settings → Users**. + +### Importing Users from Plex + +Clicking the **Import Users from Plex** button on the **User List** page will fetch the list of users with access to the Plex server from [plex.tv](https://www.plex.tv/), and add them to Overseerr automatically. + +Importing Plex users is not required, however. Any user with access to the Plex server can log in to Overseerr even if they have not been imported, and will be assigned the configured [default permissions](../settings/README.md#default-user-permissions) upon their first login. + +### Creating Local Users + +If you would like to grant Overseerr access to a user who doesn't have their own Plex account and/or access to the Plex server, you can manually add them by clicking the **Create Local User** button. + +#### Email Address + +Enter a valid email address at which the user can receive messages pertaining to their account and other notifications. The email address currently cannot be modified after the account is created. + +#### Automatically Generate Password + +If [email notifications](../notifications/email.md) have been configured and enabled, Overseerr can automatically generate a password for the new user. + +#### Password + +If you would prefer to manually configure a password, enter a password here that is a minimum of 8 characters. + +## Editing Users + +From the **User List**, you can click the **Edit** button to modify a particular user's settings. + +You can also click the check boxes and click the **Bulk Edit** button to set user permissions for multiple users at once. + +### General + +#### Display Name + +You can optionally set a "friendly name" for any user. This name will be used in lieu of their Plex username (for users imported from Plex) or their email address (for manually-created local users). + +#### Discover Region & Discover Language + +Users can override the [global filter settings](../settings/README.md#discover-region-and-discover-language) to suit their own preferences. + +#### Movie Request Limit & Series Request Limit + +You can override the default settings and assign different request limits for specific users by checking the **Enable Override** box and selecting the desired request limit and time period. + +Unless an override is configured, users are granted the global request limits. + +Note that users with the **Manage Users** permission are exempt from request limits, since that permission also grants the ability to submit requests on behalf of other users. + +Users are also unable to modify their own request limits. + +### Password + +All "local users" are assigned passwords upon creation, but users imported from Plex can also optionally configure passwords to enable sign-in using their email address. + +Passwords must be a minimum of 8 characters long. + +### Notifications + +Users can configure their personal notification settings here. Please see [Notifications](../notifications/README.md) for details on configuring and enabling notifications. + +### Permissions + +Users cannot modify their own permissions. Users with the **Manage Users** permission can manage permissions of other users, except those of users with the **Admin** permission. + +## Deleting Users + +When users are deleted, all of their data and request history is also cleared from the database. diff --git a/overseerr-api.yml b/overseerr-api.yml index 0fdfdcea..08bf1b5c 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -92,17 +92,12 @@ components: UserSettings: type: object properties: - enableNotifications: - type: boolean - default: true discordId: type: string - telegramChatId: + region: + type: string + language: type: string - telegramSendSilently: - type: boolean - required: - - enableNotifications MainSettings: type: object properties: @@ -200,9 +195,6 @@ components: message: type: string example: 'OK' - host: - type: string - example: '127-0-0-1.2ab6ce1a093d465e910def96cf4e4799.plex.direct' required: - protocol - address @@ -441,6 +433,15 @@ components: - is4k - enableSeasonFolders - isDefault + ServarrTag: + type: object + properties: + id: + type: number + example: 1 + label: + type: string + example: A Label PublicSettings: type: object properties: @@ -1195,12 +1196,6 @@ components: type: string priority: type: number - NotificationSettings: - type: object - properties: - enabled: - type: boolean - example: true NotificationEmailSettings: type: object properties: @@ -1553,20 +1548,30 @@ components: UserSettingsNotifications: type: object properties: - enableNotifications: + notificationAgents: + type: number + example: 0 + emailEnabled: + type: boolean + pgpKey: + type: string + nullable: true + discordEnabled: type: boolean - default: true discordId: type: string nullable: true + telegramEnabled: + type: boolean + telegramBotUsername: + type: string + nullable: true telegramChatId: type: string nullable: true telegramSendSilently: type: boolean nullable: true - required: - - enableNotifications securitySchemes: cookieAuth: type: apiKey @@ -2300,37 +2305,6 @@ paths: timestamp: type: string example: 2020-12-15T16:20:00.069Z - /settings/notifications: - get: - summary: Return notification settings - description: Returns current notification settings in a JSON object. - tags: - - settings - responses: - '200': - description: Returned settings - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSettings' - post: - summary: Update notification settings - description: Updates notification settings with the provided values. - tags: - - settings - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSettings' - responses: - '200': - description: 'Values were sucessfully updated' - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationSettings' /settings/notifications/email: get: summary: Get email notification settings diff --git a/package.json b/package.json index 4a79ed44..e7876f0a 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ }, "license": "MIT", "dependencies": { - "@headlessui/react": "^0.3.1", + "@headlessui/react": "^1.0.0", "@supercharge/request-ip": "^1.1.2", "@svgr/webpack": "^5.5.0", - "@tanem/react-nprogress": "^3.0.60", + "@tanem/react-nprogress": "^3.0.62", "ace-builds": "^1.4.12", "axios": "^0.21.1", "bcrypt": "^5.0.1", @@ -33,14 +33,14 @@ "csurf": "^1.11.0", "email-templates": "^8.0.4", "express": "^4.17.1", - "express-openapi-validator": "^4.12.6", + "express-openapi-validator": "^4.12.7", "express-rate-limit": "^5.2.6", "express-session": "^1.17.1", "formik": "^2.2.6", "gravatar-url": "^3.1.0", "intl": "^1.2.5", "lodash": "^4.17.21", - "next": "10.1.2", + "next": "10.1.3", "node-cache": "^5.1.2", "node-schedule": "^2.0.0", "nodemailer": "^6.5.0", @@ -53,8 +53,8 @@ "react-animate-height": "^2.0.23", "react-dom": "17.0.2", "react-intersection-observer": "^8.31.0", - "react-intl": "5.13.5", - "react-markdown": "^5.0.3", + "react-intl": "5.15.8", + "react-markdown": "^6.0.0", "react-select": "^4.3.0", "react-spring": "^8.0.27", "react-toast-notifications": "^2.4.3", @@ -69,15 +69,15 @@ "typeorm": "^0.2.32", "uuid": "^8.3.2", "winston": "^3.3.3", - "winston-daily-rotate-file": "^4.5.1", + "winston-daily-rotate-file": "^4.5.2", "xml2js": "^0.4.23", "yamljs": "^0.3.0", "yup": "^0.32.9" }, "devDependencies": { "@babel/cli": "^7.13.14", - "@commitlint/cli": "^12.0.1", - "@commitlint/config-conventional": "^12.0.1", + "@commitlint/cli": "^12.1.1", + "@commitlint/config-conventional": "^12.1.1", "@semantic-release/changelog": "^5.0.1", "@semantic-release/commit-analyzer": "^8.0.1", "@semantic-release/exec": "^5.0.0", @@ -85,22 +85,22 @@ "@tailwindcss/aspect-ratio": "^0.2.0", "@tailwindcss/forms": "^0.3.2", "@tailwindcss/typography": "^0.4.0", - "@types/bcrypt": "^3.0.0", + "@types/bcrypt": "^3.0.1", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/country-flag-icons": "^1.2.0", - "@types/csurf": "^1.11.0", - "@types/email-templates": "^8.0.2", + "@types/csurf": "^1.11.1", + "@types/email-templates": "^8.0.3", "@types/express": "^4.17.11", "@types/express-rate-limit": "^5.1.1", "@types/express-session": "^1.17.3", "@types/lodash": "^4.14.168", - "@types/node": "^14.14.37", + "@types/node": "^14.14.41", "@types/node-schedule": "^1.3.1", "@types/nodemailer": "^6.4.1", "@types/react": "^17.0.3", "@types/react-dom": "^17.0.3", - "@types/react-select": "^4.0.13", + "@types/react-select": "^4.0.15", "@types/react-toast-notifications": "^2.4.0", "@types/react-transition-group": "^4.4.1", "@types/secure-random-password": "^0.2.0", @@ -109,32 +109,32 @@ "@types/xml2js": "^0.4.8", "@types/yamljs": "^0.2.31", "@types/yup": "^0.29.11", - "@typescript-eslint/eslint-plugin": "^4.20.0", - "@typescript-eslint/parser": "^4.20.0", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", "autoprefixer": "^10.2.5", "babel-plugin-react-intl": "^8.2.25", "babel-plugin-react-intl-auto": "^3.3.0", "commitizen": "^4.2.3", "copyfiles": "^2.4.1", "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.23.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-formatjs": "^2.14.3", + "eslint": "^7.24.0", + "eslint-config-prettier": "^8.2.0", + "eslint-plugin-formatjs": "^2.14.6", "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-react": "^7.23.1", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", "extract-react-intl-messages": "^4.1.1", "husky": "4.3.8", "lint-staged": "^10.5.4", "nodemon": "^2.0.7", - "postcss": "^8.2.9", + "postcss": "^8.2.10", "prettier": "^2.2.1", "semantic-release": "^17.4.2", "semantic-release-docker-buildx": "^1.0.1", - "tailwindcss": "^2.0.4", + "tailwindcss": "^2.1.1", "ts-node": "^9.1.1", - "typescript": "^4.2.3" + "typescript": "^4.2.4" }, "resolutions": { "sqlite3/node-gyp": "^5.1.0" diff --git a/public/preview.jpg b/public/preview.jpg index 8abdaa1e..946ef07a 100644 Binary files a/public/preview.jpg and b/public/preview.jpg differ diff --git a/server/api/github.ts b/server/api/github.ts new file mode 100644 index 00000000..48b8854b --- /dev/null +++ b/server/api/github.ts @@ -0,0 +1,133 @@ +import cacheManager from '../lib/cache'; +import logger from '../logger'; +import ExternalAPI from './externalapi'; + +interface GitHubRelease { + url: string; + assets_url: string; + upload_url: string; + html_url: string; + id: number; + node_id: string; + tag_name: string; + target_commitish: string; + name: string; + draft: boolean; + prerelease: boolean; + created_at: string; + published_at: string; + tarball_url: string; + zipball_url: string; + body: string; +} + +interface GithubCommit { + sha: string; + node_id: string; + commit: { + author: { + name: string; + email: string; + date: string; + }; + committer: { + name: string; + email: string; + date: string; + }; + message: string; + tree: { + sha: string; + url: string; + }; + url: string; + comment_count: number; + verification: { + verified: boolean; + reason: string; + signature: string; + payload: string; + }; + }; + url: string; + html_url: string; + comments_url: string; + parents: [ + { + sha: string; + url: string; + html_url: string; + } + ]; +} + +class GithubAPI extends ExternalAPI { + constructor() { + super( + 'https://api.github.com', + {}, + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + nodeCache: cacheManager.getCache('github').data, + } + ); + } + + public async getOverseerrReleases({ + take = 20, + }: { + take?: number; + } = {}): Promise { + try { + const data = await this.get( + '/repos/sct/overseerr/releases', + { + params: { + per_page: take, + }, + } + ); + + return data; + } catch (e) { + logger.warn( + "Failed to retrieve GitHub releases. This may be an issue on GitHub's end. Overseerr can't check if it's on the latest version.", + { label: 'GitHub API', errorMessage: e.message } + ); + return []; + } + } + + public async getOverseerrCommits({ + take = 20, + branch = 'develop', + }: { + take?: number; + branch?: string; + } = {}): Promise { + try { + const data = await this.get( + '/repos/sct/overseerr/commits', + { + params: { + per_page: take, + branch, + }, + } + ); + + return data; + } catch (e) { + logger.warn( + "Failed to retrieve GitHub commits. This may be an issue on GitHub's end. Overseerr can't check if it's on the latest version.", + { label: 'GitHub API', errorMessage: e.message } + ); + return []; + } + } +} + +export default GithubAPI; diff --git a/server/api/plextv.ts b/server/api/plextv.ts index 5d93f956..9efcecc2 100644 --- a/server/api/plextv.ts +++ b/server/api/plextv.ts @@ -91,7 +91,7 @@ interface FriendResponse { email: string; thumb: string; }; - Server: ServerResponse[]; + Server?: ServerResponse[]; }[]; }; } @@ -232,7 +232,7 @@ class PlexTvAPI { ); } - return !!user.Server.find( + return !!user.Server?.find( (server) => server.$.machineIdentifier === settings.plex.machineId ); } catch (e) { diff --git a/server/api/servarr/base.ts b/server/api/servarr/base.ts new file mode 100644 index 00000000..75f138b5 --- /dev/null +++ b/server/api/servarr/base.ts @@ -0,0 +1,169 @@ +import cacheManager, { AvailableCacheIds } from '../../lib/cache'; +import { DVRSettings } from '../../lib/settings'; +import ExternalAPI from '../externalapi'; + +export interface RootFolder { + id: number; + path: string; + freeSpace: number; + totalSpace: number; + unmappedFolders: { + name: string; + path: string; + }[]; +} + +export interface QualityProfile { + id: number; + name: string; +} + +interface QueueItem { + size: number; + title: string; + sizeleft: number; + timeleft: string; + estimatedCompletionTime: string; + status: string; + trackedDownloadStatus: string; + trackedDownloadState: string; + downloadId: string; + protocol: string; + downloadClient: string; + indexer: string; + id: number; +} + +export interface Tag { + id: number; + label: string; +} + +interface QueueResponse { + page: number; + pageSize: number; + sortKey: string; + sortDirection: string; + totalRecords: number; + records: (QueueItem & QueueItemAppendT)[]; +} + +class ServarrBase extends ExternalAPI { + static buildUrl(settings: DVRSettings, path?: string): string { + return `${settings.useSsl ? 'https' : 'http'}://${settings.hostname}:${ + settings.port + }${settings.baseUrl ?? ''}${path}`; + } + + protected apiName: string; + + constructor({ + url, + apiKey, + cacheName, + apiName, + }: { + url: string; + apiKey: string; + cacheName: AvailableCacheIds; + apiName: string; + }) { + super( + url, + { + apikey: apiKey, + }, + { + nodeCache: cacheManager.getCache(cacheName).data, + } + ); + + this.apiName = apiName; + } + + public getProfiles = async (): Promise => { + try { + const data = await this.getRolling( + `/qualityProfile`, + undefined, + 3600 + ); + + return data; + } catch (e) { + throw new Error( + `[${this.apiName}] Failed to retrieve profiles: ${e.message}` + ); + } + }; + + public getRootFolders = async (): Promise => { + try { + const data = await this.getRolling( + `/rootfolder`, + undefined, + 3600 + ); + + return data; + } catch (e) { + throw new Error( + `[${this.apiName}] Failed to retrieve root folders: ${e.message}` + ); + } + }; + + public getQueue = async (): Promise<(QueueItem & QueueItemAppendT)[]> => { + try { + const response = await this.axios.get>( + `/queue` + ); + + return response.data.records; + } catch (e) { + throw new Error( + `[${this.apiName}] Failed to retrieve queue: ${e.message}` + ); + } + }; + + public getTags = async (): Promise => { + try { + const response = await this.axios.get(`/tag`); + + return response.data; + } catch (e) { + throw new Error( + `[${this.apiName}] Failed to retrieve tags: ${e.message}` + ); + } + }; + + public createTag = async ({ label }: { label: string }): Promise => { + try { + const response = await this.axios.post(`/tag`, { + label, + }); + + return response.data; + } catch (e) { + throw new Error(`[${this.apiName}] Failed to create tag: ${e.message}`); + } + }; + + protected async runCommand( + commandName: string, + options: Record + ): Promise { + try { + await this.axios.post(`/command`, { + name: commandName, + ...options, + }); + } catch (e) { + throw new Error(`[${this.apiName}] Failed to run command: ${e.message}`); + } + } +} + +export default ServarrBase; diff --git a/server/api/radarr.ts b/server/api/servarr/radarr.ts similarity index 68% rename from server/api/radarr.ts rename to server/api/servarr/radarr.ts index 187a52ba..59407720 100644 --- a/server/api/radarr.ts +++ b/server/api/servarr/radarr.ts @@ -1,12 +1,11 @@ -import cacheManager from '../lib/cache'; -import { RadarrSettings } from '../lib/settings'; -import logger from '../logger'; -import ExternalAPI from './externalapi'; +import logger from '../../logger'; +import ServarrBase from './base'; interface RadarrMovieOptions { title: string; qualityProfileId: number; minimumAvailability: string; + tags: number[]; profileId: number; year: number; rootFolderPath: string; @@ -32,65 +31,9 @@ export interface RadarrMovie { hasFile: boolean; } -export interface RadarrRootFolder { - id: number; - path: string; - freeSpace: number; - totalSpace: number; - unmappedFolders: { - name: string; - path: string; - }[]; -} - -export interface RadarrProfile { - id: number; - name: string; -} - -interface QueueItem { - movieId: number; - size: number; - title: string; - sizeleft: number; - timeleft: string; - estimatedCompletionTime: string; - status: string; - trackedDownloadStatus: string; - trackedDownloadState: string; - downloadId: string; - protocol: string; - downloadClient: string; - indexer: string; - id: number; -} - -interface QueueResponse { - page: number; - pageSize: number; - sortKey: string; - sortDirection: string; - totalRecords: number; - records: QueueItem[]; -} - -class RadarrAPI extends ExternalAPI { - static buildRadarrUrl(radarrSettings: RadarrSettings, path?: string): string { - return `${radarrSettings.useSsl ? 'https' : 'http'}://${ - radarrSettings.hostname - }:${radarrSettings.port}${radarrSettings.baseUrl ?? ''}${path}`; - } - +class RadarrAPI extends ServarrBase<{ movieId: number }> { constructor({ url, apiKey }: { url: string; apiKey: string }) { - super( - url, - { - apikey: apiKey, - }, - { - nodeCache: cacheManager.getCache('radarr').data, - } - ); + super({ url, apiKey, cacheName: 'radarr', apiName: 'Radarr' }); } public getMovies = async (): Promise => { @@ -162,6 +105,7 @@ class RadarrAPI extends ExternalAPI { minimumAvailability: options.minimumAvailability, tmdbId: options.tmdbId, year: options.year, + tags: options.tags, rootFolderPath: options.rootFolderPath, monitored: options.monitored, addOptions: { @@ -206,6 +150,7 @@ class RadarrAPI extends ExternalAPI { year: options.year, rootFolderPath: options.rootFolderPath, monitored: options.monitored, + tags: options.tags, addOptions: { searchForMovie: options.searchNow, }, @@ -238,44 +183,6 @@ class RadarrAPI extends ExternalAPI { throw new Error('Failed to add movie to Radarr'); } }; - - public getProfiles = async (): Promise => { - try { - const data = await this.getRolling( - `/qualityProfile`, - undefined, - 3600 - ); - - return data; - } catch (e) { - throw new Error(`[Radarr] Failed to retrieve profiles: ${e.message}`); - } - }; - - public getRootFolders = async (): Promise => { - try { - const data = await this.getRolling( - `/rootfolder`, - undefined, - 3600 - ); - - return data; - } catch (e) { - throw new Error(`[Radarr] Failed to retrieve root folders: ${e.message}`); - } - }; - - public getQueue = async (): Promise => { - try { - const response = await this.axios.get(`/queue`); - - return response.data.records; - } catch (e) { - throw new Error(`[Radarr] Failed to retrieve queue: ${e.message}`); - } - }; } export default RadarrAPI; diff --git a/server/api/sonarr.ts b/server/api/servarr/sonarr.ts similarity index 69% rename from server/api/sonarr.ts rename to server/api/servarr/sonarr.ts index e2e8bd19..12337839 100644 --- a/server/api/sonarr.ts +++ b/server/api/servarr/sonarr.ts @@ -1,7 +1,5 @@ -import cacheManager from '../lib/cache'; -import { SonarrSettings } from '../lib/settings'; -import logger from '../logger'; -import ExternalAPI from './externalapi'; +import logger from '../../logger'; +import ServarrBase from './base'; interface SonarrSeason { seasonNumber: number; @@ -49,7 +47,7 @@ export interface SonarrSeries { titleSlug: string; certification: string; genres: string[]; - tags: string[]; + tags: number[]; added: string; ratings: { votes: number; @@ -65,49 +63,6 @@ export interface SonarrSeries { }; } -interface QueueItem { - seriesId: number; - episodeId: number; - size: number; - title: string; - sizeleft: number; - timeleft: string; - estimatedCompletionTime: string; - status: string; - trackedDownloadStatus: string; - trackedDownloadState: string; - downloadId: string; - protocol: string; - downloadClient: string; - indexer: string; - id: number; -} - -interface QueueResponse { - page: number; - pageSize: number; - sortKey: string; - sortDirection: string; - totalRecords: number; - records: QueueItem[]; -} - -interface SonarrProfile { - id: number; - name: string; -} - -interface SonarrRootFolder { - id: number; - path: string; - freeSpace: number; - totalSpace: number; - unmappedFolders: { - name: string; - path: string; - }[]; -} - interface AddSeriesOptions { tvdbid: number; title: string; @@ -116,6 +71,7 @@ interface AddSeriesOptions { seasons: number[]; seasonFolder: boolean; rootFolderPath: string; + tags?: number[]; seriesType: SonarrSeries['seriesType']; monitored?: boolean; searchNow?: boolean; @@ -126,23 +82,9 @@ export interface LanguageProfile { name: string; } -class SonarrAPI extends ExternalAPI { - static buildSonarrUrl(sonarrSettings: SonarrSettings, path?: string): string { - return `${sonarrSettings.useSsl ? 'https' : 'http'}://${ - sonarrSettings.hostname - }:${sonarrSettings.port}${sonarrSettings.baseUrl ?? ''}${path}`; - } - +class SonarrAPI extends ServarrBase<{ seriesId: number; episodeId: number }> { constructor({ url, apiKey }: { url: string; apiKey: string }) { - super( - url, - { - apikey: apiKey, - }, - { - nodeCache: cacheManager.getCache('sonarr').data, - } - ); + super({ url, apiKey, apiName: 'Sonarr', cacheName: 'sonarr' }); } public async getSeries(): Promise { @@ -151,7 +93,7 @@ class SonarrAPI extends ExternalAPI { return response.data; } catch (e) { - throw new Error(`[Radarr] Failed to retrieve series: ${e.message}`); + throw new Error(`[Sonarr] Failed to retrieve series: ${e.message}`); } } @@ -205,6 +147,7 @@ class SonarrAPI extends ExternalAPI { // If the series already exists, we will simply just update it if (series.id) { + series.tags = options.tags ?? series.tags; series.seasons = this.buildSeasonList(options.seasons, series.seasons); const newSeriesResponse = await this.axios.put( @@ -249,6 +192,7 @@ class SonarrAPI extends ExternalAPI { monitored: false, })) ), + tags: options.tags, seasonFolder: options.seasonFolder, monitored: options.monitored, rootFolderPath: options.rootFolderPath, @@ -286,46 +230,6 @@ class SonarrAPI extends ExternalAPI { } } - public async getProfiles(): Promise { - try { - const data = await this.getRolling( - '/qualityProfile', - undefined, - 3600 - ); - - return data; - } catch (e) { - logger.error('Something went wrong while retrieving Sonarr profiles.', { - label: 'Sonarr API', - message: e.message, - }); - throw new Error('Failed to get profiles'); - } - } - - public async getRootFolders(): Promise { - try { - const data = await this.getRolling( - '/rootfolder', - undefined, - 3600 - ); - - return data; - } catch (e) { - logger.error( - 'Something went wrong while retrieving Sonarr root folders.', - { - label: 'Sonarr API', - message: e.message, - } - ); - - throw new Error('Failed to get root folders'); - } - } - public async getLanguageProfiles(): Promise { try { const data = await this.getRolling( @@ -356,25 +260,6 @@ class SonarrAPI extends ExternalAPI { await this.runCommand('SeriesSearch', { seriesId }); } - private async runCommand( - commandName: string, - options: Record - ): Promise { - try { - await this.axios.post(`/command`, { - name: commandName, - ...options, - }); - } catch (e) { - logger.error('Something went wrong attempting to run a Sonarr command.', { - label: 'Sonarr API', - message: e.message, - }); - - throw new Error('Failed to run Sonarr command.'); - } - } - private buildSeasonList( seasons: number[], existingSeasons?: SonarrSeason[] @@ -399,16 +284,6 @@ class SonarrAPI extends ExternalAPI { return newSeasons; } - - public getQueue = async (): Promise => { - try { - const response = await this.axios.get(`/queue`); - - return response.data.records; - } catch (e) { - throw new Error(`[Radarr] Failed to retrieve queue: ${e.message}`); - } - }; } export default SonarrAPI; diff --git a/server/api/themoviedb/index.ts b/server/api/themoviedb/index.ts index c52e971b..3436e1bd 100644 --- a/server/api/themoviedb/index.ts +++ b/server/api/themoviedb/index.ts @@ -715,7 +715,34 @@ class TheMovieDb extends ExternalAPI { 86400 // 24 hours ); - const movieGenres = sortBy(data.genres, 'name'); + if ( + !language.startsWith('en') && + data.genres.some((genre) => !genre.name) + ) { + const englishData = await this.get( + '/genre/movie/list', + { + params: { + language: 'en', + }, + }, + 86400 // 24 hours + ); + + data.genres + .filter((genre) => !genre.name) + .forEach((genre) => { + genre.name = + englishData.genres.find( + (englishGenre) => englishGenre.id === genre.id + )?.name ?? ''; + }); + } + + const movieGenres = sortBy( + data.genres.filter((genre) => genre.name), + 'name' + ); return movieGenres; } catch (e) { @@ -739,7 +766,34 @@ class TheMovieDb extends ExternalAPI { 86400 // 24 hours ); - const tvGenres = sortBy(data.genres, 'name'); + if ( + !language.startsWith('en') && + data.genres.some((genre) => !genre.name) + ) { + const englishData = await this.get( + '/genre/tv/list', + { + params: { + language: 'en', + }, + }, + 86400 // 24 hours + ); + + data.genres + .filter((genre) => !genre.name) + .forEach((genre) => { + genre.name = + englishData.genres.find( + (englishGenre) => englishGenre.id === genre.id + )?.name ?? ''; + }); + } + + const tvGenres = sortBy( + data.genres.filter((genre) => genre.name), + 'name' + ); return tvGenres; } catch (e) { diff --git a/server/entity/Media.ts b/server/entity/Media.ts index 9ca195c6..3d821651 100644 --- a/server/entity/Media.ts +++ b/server/entity/Media.ts @@ -1,23 +1,23 @@ import { - Entity, - PrimaryGeneratedColumn, + AfterLoad, Column, - Index, - OneToMany, CreateDateColumn, - UpdateDateColumn, + Entity, getRepository, In, - AfterLoad, + Index, + OneToMany, + PrimaryGeneratedColumn, + UpdateDateColumn, } from 'typeorm'; -import { MediaRequest } from './MediaRequest'; +import RadarrAPI from '../api/servarr/radarr'; +import SonarrAPI from '../api/servarr/sonarr'; import { MediaStatus, MediaType } from '../constants/media'; -import logger from '../logger'; -import Season from './Season'; -import { getSettings } from '../lib/settings'; -import RadarrAPI from '../api/radarr'; import downloadTracker, { DownloadingItem } from '../lib/downloadtracker'; -import SonarrAPI from '../api/sonarr'; +import { getSettings } from '../lib/settings'; +import logger from '../logger'; +import { MediaRequest } from './MediaRequest'; +import Season from './Season'; @Entity() class Media { @@ -168,10 +168,7 @@ class Media { if (server) { this.serviceUrl = server.externalUrl ? `${server.externalUrl}/movie/${this.externalServiceSlug}` - : RadarrAPI.buildRadarrUrl( - server, - `/movie/${this.externalServiceSlug}` - ); + : RadarrAPI.buildUrl(server, `/movie/${this.externalServiceSlug}`); } } @@ -184,7 +181,7 @@ class Media { if (server) { this.serviceUrl4k = server.externalUrl ? `${server.externalUrl}/movie/${this.externalServiceSlug4k}` - : RadarrAPI.buildRadarrUrl( + : RadarrAPI.buildUrl( server, `/movie/${this.externalServiceSlug4k}` ); @@ -202,10 +199,7 @@ class Media { if (server) { this.serviceUrl = server.externalUrl ? `${server.externalUrl}/series/${this.externalServiceSlug}` - : SonarrAPI.buildSonarrUrl( - server, - `/series/${this.externalServiceSlug}` - ); + : SonarrAPI.buildUrl(server, `/series/${this.externalServiceSlug}`); } } @@ -218,7 +212,7 @@ class Media { if (server) { this.serviceUrl4k = server.externalUrl ? `${server.externalUrl}/series/${this.externalServiceSlug4k}` - : SonarrAPI.buildSonarrUrl( + : SonarrAPI.buildUrl( server, `/series/${this.externalServiceSlug4k}` ); diff --git a/server/entity/MediaRequest.ts b/server/entity/MediaRequest.ts index 6e5c1135..167d1db0 100644 --- a/server/entity/MediaRequest.ts +++ b/server/entity/MediaRequest.ts @@ -1,28 +1,29 @@ +import { isEqual } from 'lodash'; import { - Entity, - PrimaryGeneratedColumn, - ManyToOne, + AfterInsert, + AfterRemove, + AfterUpdate, Column, CreateDateColumn, - UpdateDateColumn, - AfterUpdate, - AfterInsert, + Entity, getRepository, + ManyToOne, OneToMany, - AfterRemove, + PrimaryGeneratedColumn, RelationCount, + UpdateDateColumn, } from 'typeorm'; -import { User } from './User'; -import Media from './Media'; -import { MediaStatus, MediaRequestStatus, MediaType } from '../constants/media'; -import { getSettings } from '../lib/settings'; +import RadarrAPI from '../api/servarr/radarr'; +import SonarrAPI, { SonarrSeries } from '../api/servarr/sonarr'; import TheMovieDb from '../api/themoviedb'; import { ANIME_KEYWORD_ID } from '../api/themoviedb/constants'; -import RadarrAPI from '../api/radarr'; -import logger from '../logger'; -import SeasonRequest from './SeasonRequest'; -import SonarrAPI, { SonarrSeries } from '../api/sonarr'; +import { MediaRequestStatus, MediaStatus, MediaType } from '../constants/media'; import notificationManager, { Notification } from '../lib/notifications'; +import { getSettings } from '../lib/settings'; +import logger from '../logger'; +import Media from './Media'; +import SeasonRequest from './SeasonRequest'; +import { User } from './User'; @Entity() export class MediaRequest { @@ -85,6 +86,37 @@ export class MediaRequest { @Column({ nullable: true }) public languageProfileId: number; + @Column({ + type: 'text', + nullable: true, + transformer: { + from: (value: string | null): number[] | null => { + if (value) { + if (value === 'none') { + return []; + } + return value.split(',').map((v) => Number(v)); + } + return null; + }, + to: (value: number[] | null): string | null => { + if (value) { + const finalValue = value.join(','); + + // We want to keep the actual state of an "empty array" so we use + // the keyword "none" to track this. + if (!finalValue) { + return 'none'; + } + + return finalValue; + } + return null; + }, + }, + }) + public tags?: number[]; + constructor(init?: Partial) { Object.assign(this, init); } @@ -113,7 +145,6 @@ export class MediaRequest { subject: movie.title, message: movie.overview, image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`, - notifyUser: this.requestedBy, media, request: this, }); @@ -125,7 +156,6 @@ export class MediaRequest { subject: tv.name, message: tv.overview, image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`, - notifyUser: this.requestedBy, media, extra: [ { @@ -200,7 +230,7 @@ export class MediaRequest { subject: tv.name, message: tv.overview, image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`, - notifyUser: this.requestedBy, + notifyUser: autoApproved ? undefined : this.requestedBy, media, extra: [ { @@ -329,7 +359,7 @@ export class MediaRequest { const settings = getSettings(); if (settings.radarr.length === 0 && !settings.radarr[0]) { logger.info( - 'Skipped radarr request as there is no radarr configured', + 'Skipped Radarr request as there is no Radarr server configured', { label: 'Media Request' } ); return; @@ -357,7 +387,9 @@ export class MediaRequest { logger.info( `There is no default ${ this.is4k ? '4K ' : '' - }radarr configured. Did you set any of your Radarr servers as default?`, + }Radarr server configured. Did you set any of your ${ + this.is4k ? '4K ' : '' + }Radarr servers as default?`, { label: 'Media Request' } ); return; @@ -365,6 +397,7 @@ export class MediaRequest { let rootFolder = radarrSettings.activeDirectory; let qualityProfile = radarrSettings.activeProfileId; + let tags = radarrSettings.tags; if ( this.rootFolder && @@ -387,10 +420,18 @@ export class MediaRequest { }); } + if (this.tags && !isEqual(this.tags, radarrSettings.tags)) { + tags = this.tags; + logger.info(`Request has override tags`, { + label: 'Media Request', + tagIds: tags, + }); + } + const tmdb = new TheMovieDb(); const radarr = new RadarrAPI({ apiKey: radarrSettings.apiKey, - url: RadarrAPI.buildRadarrUrl(radarrSettings, '/api/v3'), + url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'), }); const movie = await tmdb.getMovie({ movieId: this.media.tmdbId }); @@ -420,6 +461,7 @@ export class MediaRequest { tmdbId: movie.id, year: Number(movie.release_date.slice(0, 4)), monitored: true, + tags, searchNow: !radarrSettings.preventSearch, }) .then(async (radarrMovie) => { @@ -459,7 +501,7 @@ export class MediaRequest { }); logger.info('Sent request to Radarr', { label: 'Media Request' }); } catch (e) { - const errorMessage = `Request failed to send to radarr: ${e.message}`; + const errorMessage = `Request failed to send to Radarr: ${e.message}`; logger.error('Request failed to send to Radarr', { label: 'Media Request', errorMessage, @@ -479,7 +521,7 @@ export class MediaRequest { const settings = getSettings(); if (settings.sonarr.length === 0 && !settings.sonarr[0]) { logger.info( - 'Skipped sonarr request as there is no sonarr configured', + 'Skipped Sonarr request as there is no Sonarr server configured', { label: 'Media Request' } ); return; @@ -507,7 +549,9 @@ export class MediaRequest { logger.info( `There is no default ${ this.is4k ? '4K ' : '' - }sonarr configured. Did you set any of your Sonarr servers as default?`, + }Sonarr server configured. Did you set any of your ${ + this.is4k ? '4K ' : '' + }Sonarr servers as default?`, { label: 'Media Request' } ); return; @@ -531,7 +575,7 @@ export class MediaRequest { const tmdb = new TheMovieDb(); const sonarr = new SonarrAPI({ apiKey: sonarrSettings.apiKey, - url: SonarrAPI.buildSonarrUrl(sonarrSettings, '/api/v3'), + url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'), }); const series = await tmdb.getTvShow({ tvId: media.tmdbId }); const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId; @@ -568,6 +612,11 @@ export class MediaRequest { ? sonarrSettings.activeAnimeLanguageProfileId : sonarrSettings.activeLanguageProfileId; + let tags = + seriesType === 'anime' + ? sonarrSettings.animeTags + : sonarrSettings.tags; + if ( this.rootFolder && this.rootFolder !== '' && @@ -599,6 +648,14 @@ export class MediaRequest { ); } + if (this.tags && !isEqual(this.tags, tags)) { + tags = this.tags; + logger.info(`Request has override tags`, { + label: 'Media Request', + tagIds: tags, + }); + } + // Run this asynchronously so we don't wait for it on the UI side sonarr .addSeries({ @@ -610,6 +667,7 @@ export class MediaRequest { seasons: this.seasons.map((season) => season.seasonNumber), seasonFolder: sonarrSettings.enableSeasonFolders, seriesType, + tags, monitored: true, searchNow: !sonarrSettings.preventSearch, }) @@ -659,7 +717,7 @@ export class MediaRequest { }); logger.info('Sent request to Sonarr', { label: 'Media Request' }); } catch (e) { - const errorMessage = `Request failed to send to sonarr: ${e.message}`; + const errorMessage = `Request failed to send to Sonarr: ${e.message}`; logger.error('Request failed to send to Sonarr', { label: 'Media Request', errorMessage, diff --git a/server/entity/User.ts b/server/entity/User.ts index db5fa950..25b57f71 100644 --- a/server/entity/User.ts +++ b/server/entity/User.ts @@ -157,7 +157,8 @@ export class User { logger.info(`Sending generated password email for ${this.email}`, { label: 'User Management', }); - const email = new PreparedEmail(); + + const email = new PreparedEmail(getSettings().notifications.agents.email); await email.send({ template: path.join(__dirname, '../templates/email/generatedpassword'), message: { @@ -193,7 +194,7 @@ export class User { logger.info(`Sending reset password email for ${this.email}`, { label: 'User Management', }); - const email = new PreparedEmail(); + const email = new PreparedEmail(getSettings().notifications.agents.email); await email.send({ template: path.join(__dirname, '../templates/email/resetpassword'), message: { @@ -236,11 +237,9 @@ export class User { const movieDate = new Date(); if (movieQuotaDays) { movieDate.setDate(movieDate.getDate() - movieQuotaDays); - } else { - movieDate.setDate(0); } - // YYYY-MM-DD format - const movieQuotaStartDate = movieDate.toJSON().split('T')[0]; + const movieQuotaStartDate = movieDate.toJSON(); + const movieQuotaUsed = movieQuotaLimit ? await requestRepository.count({ where: { @@ -261,11 +260,8 @@ export class User { const tvDate = new Date(); if (tvQuotaDays) { tvDate.setDate(tvDate.getDate() - tvQuotaDays); - } else { - tvDate.setDate(0); } - // YYYY-MM-DD format - const tvQuotaStartDate = tvDate.toJSON().split('T')[0]; + const tvQuotaStartDate = tvDate.toJSON(); const tvQuotaUsed = tvQuotaLimit ? ( await requestRepository diff --git a/server/entity/UserSettings.ts b/server/entity/UserSettings.ts index 8e60865a..023a1bde 100644 --- a/server/entity/UserSettings.ts +++ b/server/entity/UserSettings.ts @@ -5,6 +5,10 @@ import { OneToOne, PrimaryGeneratedColumn, } from 'typeorm'; +import { + hasNotificationAgentEnabled, + NotificationAgentType, +} from '../lib/notifications/agenttypes'; import { User } from './User'; @Entity() @@ -20,8 +24,17 @@ export class UserSettings { @JoinColumn() public user: User; - @Column({ default: true }) - public enableNotifications: boolean; + @Column({ nullable: true }) + public region?: string; + + @Column({ nullable: true }) + public originalLanguage?: string; + + @Column({ type: 'integer', default: NotificationAgentType.EMAIL }) + public notificationAgents = NotificationAgentType.EMAIL; + + @Column({ nullable: true }) + public pgpKey?: string; @Column({ nullable: true }) public discordId?: string; @@ -32,12 +45,7 @@ export class UserSettings { @Column({ nullable: true }) public telegramSendSilently?: boolean; - @Column({ nullable: true }) - public region?: string; - - @Column({ nullable: true }) - public originalLanguage?: string; - - @Column({ nullable: true }) - public pgpKey?: string; + public hasNotificationAgentEnabled(agent: NotificationAgentType): boolean { + return !!hasNotificationAgentEnabled(agent, this.notificationAgents); + } } diff --git a/server/interfaces/api/plexInterfaces.ts b/server/interfaces/api/plexInterfaces.ts index 42ec9cb4..5373cb58 100644 --- a/server/interfaces/api/plexInterfaces.ts +++ b/server/interfaces/api/plexInterfaces.ts @@ -14,7 +14,6 @@ export interface PlexConnection { local: boolean; status?: number; message?: string; - host?: string; } export interface PlexDevice { diff --git a/server/interfaces/api/serviceInterfaces.ts b/server/interfaces/api/serviceInterfaces.ts index 3bfa289e..1188f24c 100644 --- a/server/interfaces/api/serviceInterfaces.ts +++ b/server/interfaces/api/serviceInterfaces.ts @@ -1,5 +1,5 @@ -import { RadarrProfile, RadarrRootFolder } from '../../api/radarr'; -import { LanguageProfile } from '../../api/sonarr'; +import { QualityProfile, RootFolder, Tag } from '../../api/servarr/base'; +import { LanguageProfile } from '../../api/servarr/sonarr'; export interface ServiceCommonServer { id: number; @@ -12,11 +12,14 @@ export interface ServiceCommonServer { activeAnimeProfileId?: number; activeAnimeDirectory?: string; activeAnimeLanguageProfileId?: number; + activeTags: number[]; + activeAnimeTags?: number[]; } export interface ServiceCommonServerWithDetails { server: ServiceCommonServer; - profiles: RadarrProfile[]; - rootFolders: Partial[]; + profiles: QualityProfile[]; + rootFolders: Partial[]; languageProfiles?: LanguageProfile[]; + tags: Tag[]; } diff --git a/server/interfaces/api/settingsInterfaces.ts b/server/interfaces/api/settingsInterfaces.ts index 72ac9b8a..7c40c6db 100644 --- a/server/interfaces/api/settingsInterfaces.ts +++ b/server/interfaces/api/settingsInterfaces.ts @@ -43,3 +43,10 @@ export interface CacheItem { vsize: number; }; } + +export interface StatusResponse { + version: string; + commitTag: string; + updateAvailable: boolean; + commitsBehind: number; +} diff --git a/server/interfaces/api/userSettingsInterfaces.ts b/server/interfaces/api/userSettingsInterfaces.ts index e6d0302f..006facf0 100644 --- a/server/interfaces/api/userSettingsInterfaces.ts +++ b/server/interfaces/api/userSettingsInterfaces.ts @@ -13,10 +13,13 @@ export interface UserSettingsGeneralResponse { } export interface UserSettingsNotificationsResponse { - enableNotifications: boolean; - telegramBotUsername?: string; + notificationAgents: number; + emailEnabled?: boolean; + pgpKey?: string; + discordEnabled?: boolean; discordId?: string; + telegramEnabled?: boolean; + telegramBotUsername?: string; telegramChatId?: string; telegramSendSilently?: boolean; - pgpKey?: string; } diff --git a/server/lib/cache.ts b/server/lib/cache.ts index aaf3bd44..3aa18244 100644 --- a/server/lib/cache.ts +++ b/server/lib/cache.ts @@ -1,6 +1,6 @@ import NodeCache from 'node-cache'; -export type AvailableCacheIds = 'tmdb' | 'radarr' | 'sonarr' | 'rt'; +export type AvailableCacheIds = 'tmdb' | 'radarr' | 'sonarr' | 'rt' | 'github'; const DEFAULT_TTL = 300; const DEFAULT_CHECK_PERIOD = 120; @@ -44,6 +44,10 @@ class CacheManager { stdTtl: 43200, checkPeriod: 60 * 30, }), + github: new Cache('github', 'GitHub API', { + stdTtl: 21600, + checkPeriod: 60 * 30, + }), }; public getCache(id: AvailableCacheIds): Cache { diff --git a/server/lib/downloadtracker.ts b/server/lib/downloadtracker.ts index 9faf411a..33282285 100644 --- a/server/lib/downloadtracker.ts +++ b/server/lib/downloadtracker.ts @@ -1,6 +1,6 @@ import { uniqWith } from 'lodash'; -import RadarrAPI from '../api/radarr'; -import SonarrAPI from '../api/sonarr'; +import RadarrAPI from '../api/servarr/radarr'; +import SonarrAPI from '../api/servarr/sonarr'; import { MediaType } from '../constants/media'; import logger from '../logger'; import { getSettings } from './settings'; @@ -73,7 +73,7 @@ class DownloadTracker { if (server.syncEnabled) { const radarr = new RadarrAPI({ apiKey: server.apiKey, - url: RadarrAPI.buildRadarrUrl(server, '/api/v3'), + url: RadarrAPI.buildUrl(server, '/api/v3'), }); const queueItems = await radarr.getQueue(); @@ -140,7 +140,7 @@ class DownloadTracker { if (server.syncEnabled) { const radarr = new SonarrAPI({ apiKey: server.apiKey, - url: SonarrAPI.buildSonarrUrl(server, '/api/v3'), + url: SonarrAPI.buildUrl(server, '/api/v3'), }); const queueItems = await radarr.getQueue(); diff --git a/server/lib/email/index.ts b/server/lib/email/index.ts index abbc1632..f9c0c747 100644 --- a/server/lib/email/index.ts +++ b/server/lib/email/index.ts @@ -1,11 +1,10 @@ -import nodemailer from 'nodemailer'; import Email from 'email-templates'; -import { getSettings } from '../settings'; +import nodemailer from 'nodemailer'; +import { NotificationAgentEmail } from '../settings'; import { openpgpEncrypt } from './openpgpEncrypt'; -class PreparedEmail extends Email { - public constructor(pgpKey?: string) { - const settings = getSettings().notifications.agents.email; +class PreparedEmail extends Email { + public constructor(settings: NotificationAgentEmail, pgpKey?: string) { const transport = nodemailer.createTransport({ host: settings.options.smtpHost, port: settings.options.smtpPort, diff --git a/server/lib/notifications/agents/discord.ts b/server/lib/notifications/agents/discord.ts index cefde186..c04b4948 100644 --- a/server/lib/notifications/agents/discord.ts +++ b/server/lib/notifications/agents/discord.ts @@ -1,7 +1,11 @@ import axios from 'axios'; +import { getRepository } from 'typeorm'; import { hasNotificationType, Notification } from '..'; +import { User } from '../../../entity/User'; import logger from '../../../logger'; +import { Permission } from '../../permissions'; import { getSettings, NotificationAgentDiscord } from '../../settings'; +import { NotificationAgentType } from '../agenttypes'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; enum EmbedColors { @@ -107,7 +111,7 @@ class DiscordAgent if (payload.request) { fields.push({ name: 'Requested By', - value: payload.request?.requestedBy.displayName ?? '', + value: payload.request.requestedBy.displayName, inline: true, }); } @@ -201,7 +205,14 @@ class DiscordAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending Discord notification', { label: 'Notifications' }); + logger.debug('Sending Discord notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); + + let content = undefined; + try { const { botUsername, @@ -213,16 +224,32 @@ class DiscordAgent return false; } - const mentionedUsers: string[] = []; - let content = undefined; + if (payload.notifyUser) { + // Mention user who submitted the request + if ( + payload.notifyUser.settings?.hasNotificationAgentEnabled( + NotificationAgentType.DISCORD + ) && + payload.notifyUser.settings?.discordId + ) { + content = `<@${payload.notifyUser.settings.discordId}>`; + } + } else { + // Mention all users with the Manage Requests permission + const userRepository = getRepository(User); + const users = await userRepository.find(); - if ( - payload.notifyUser && - (payload.notifyUser.settings?.enableNotifications ?? true) && - payload.notifyUser.settings?.discordId - ) { - mentionedUsers.push(payload.notifyUser.settings.discordId); - content = `<@${payload.notifyUser.settings.discordId}>`; + content = users + .filter( + (user) => + user.hasPermission(Permission.MANAGE_REQUESTS) && + user.settings?.hasNotificationAgentEnabled( + NotificationAgentType.DISCORD + ) && + user.settings?.discordId + ) + .map((user) => `<@${user.settings?.discordId}>`) + .join(' '); } await axios.post(webhookUrl, { @@ -230,18 +257,19 @@ class DiscordAgent avatar_url: botAvatarUrl, embeds: [this.buildEmbed(type, payload)], content, - allowed_mentions: { - users: mentionedUsers, - }, } as DiscordWebhookPayload); return true; } catch (e) { logger.error('Error sending Discord notification', { label: 'Notifications', - message: e.message, + mentions: content, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, response: e.response.data, }); + return false; } } diff --git a/server/lib/notifications/agents/email.ts b/server/lib/notifications/agents/email.ts index ea6b02ef..4d00eb6f 100644 --- a/server/lib/notifications/agents/email.ts +++ b/server/lib/notifications/agents/email.ts @@ -1,3 +1,4 @@ +import { EmailOptions } from 'email-templates'; import path from 'path'; import { getRepository } from 'typeorm'; import { hasNotificationType, Notification } from '..'; @@ -7,6 +8,7 @@ import logger from '../../../logger'; import PreparedEmail from '../../email'; import { Permission } from '../../permissions'; import { getSettings, NotificationAgentEmail } from '../../settings'; +import { NotificationAgentType } from '../agenttypes'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; class EmailAgent @@ -35,379 +37,194 @@ class EmailAgent return false; } - private async sendMediaRequestEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app + private buildMessage( + type: Notification, + payload: NotificationPayload, + toEmail: string + ): EmailOptions | undefined { const { applicationUrl, applicationTitle } = getSettings().main; - try { - const userRepository = getRepository(User); - const users = await userRepository.find(); - // Send to all users with the manage requests permission (or admins) - users - .filter( - (user) => - user.hasPermission(Permission.MANAGE_REQUESTS) && - (user.settings?.enableNotifications ?? true) - ) - .forEach((user) => { - const email = new PreparedEmail(user.settings?.pgpKey); - - email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: user.email, - }, - locals: { - body: `A user has requested a new ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - }!`, - mediaName: payload.subject, - mediaPlot: payload.message, - mediaExtra: payload.extra ?? [], - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `New ${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Request`, - }, - }); - }); - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; + if (type === Notification.TEST_NOTIFICATION) { + return { + template: path.join(__dirname, '../../../templates/email/test-email'), + message: { + to: toEmail, + }, + locals: { + body: payload.message, + applicationUrl, + applicationTitle, + }, + }; } - } - private async sendMediaFailedEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - const userRepository = getRepository(User); - const users = await userRepository.find(); + if (payload.media) { + let requestType = ''; + let body = ''; - // Send to all users with the manage requests permission (or admins) - users - .filter( - (user) => - user.hasPermission(Permission.MANAGE_REQUESTS) && - (user.settings?.enableNotifications ?? true) - ) - .forEach((user) => { - const email = new PreparedEmail(user.settings?.pgpKey); - - email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: user.email, - }, - locals: { - body: `A new request for the following ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - } could not be added to ${ - payload.media?.mediaType === MediaType.TV ? 'Sonarr' : 'Radarr' - }:`, - mediaName: payload.subject, - mediaPlot: payload.message, - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `Failed ${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Request`, - }, - }); - }); - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; - } - } - - private async sendMediaApprovedEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - if ( - payload.notifyUser && - (payload.notifyUser.settings?.enableNotifications ?? true) - ) { - const email = new PreparedEmail(payload.notifyUser.settings?.pgpKey); - - await email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: payload.notifyUser.email, - }, - locals: { - body: `Your request for the following ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - } has been approved:`, - mediaName: payload.subject, - mediaExtra: payload.extra ?? [], - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Request Approved`, - }, - }); + switch (type) { + case Notification.MEDIA_PENDING: + requestType = `New ${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Request`; + body = `A user has requested a new ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + }!`; + break; + case Notification.MEDIA_APPROVED: + requestType = `${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Request Approved`; + body = `Your request for the following ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + } has been approved:`; + break; + case Notification.MEDIA_AUTO_APPROVED: + requestType = `${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Request Automatically Approved`; + body = `A new request for the following ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + } has been automatically approved:`; + break; + case Notification.MEDIA_AVAILABLE: + requestType = `${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Now Available`; + body = `The following ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + } you requested is now available!`; + break; + case Notification.MEDIA_DECLINED: + requestType = `${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Request Declined`; + body = `Your request for the following ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + } was declined:`; + break; + case Notification.MEDIA_FAILED: + requestType = `Failed ${ + payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' + } Request`; + body = `A new request for the following ${ + payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' + } could not be added to ${ + payload.media?.mediaType === MediaType.TV ? 'Sonarr' : 'Radarr' + }:`; + break; } - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; + return { + template: path.join( + __dirname, + '../../../templates/email/media-request' + ), + message: { + to: toEmail, + }, + locals: { + requestType, + body, + mediaName: payload.subject, + mediaPlot: payload.message, + mediaExtra: payload.extra ?? [], + imageUrl: payload.image, + timestamp: new Date().toTimeString(), + requestedBy: payload.request?.requestedBy.displayName, + actionUrl: applicationUrl + ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` + : undefined, + applicationUrl, + applicationTitle, + }, + }; } - } - private async sendMediaAutoApprovedEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - const userRepository = getRepository(User); - const users = await userRepository.find(); - - // Send to all users with the manage requests permission (or admins) - users - .filter( - (user) => - user.hasPermission(Permission.MANAGE_REQUESTS) && - (user.settings?.enableNotifications ?? true) - ) - .forEach((user) => { - const email = new PreparedEmail(); - - email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: user.email, - }, - locals: { - body: `A new request for the following ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - } has been automatically approved:`, - mediaName: payload.subject, - mediaExtra: payload.extra ?? [], - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Request Automatically Approved`, - }, - }); - }); - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; - } - } - - private async sendMediaDeclinedEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - if ( - payload.notifyUser && - (payload.notifyUser.settings?.enableNotifications ?? true) - ) { - const email = new PreparedEmail(payload.notifyUser.settings?.pgpKey); - - await email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: payload.notifyUser.email, - }, - locals: { - body: `Your request for the following ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - } was declined:`, - mediaName: payload.subject, - mediaExtra: payload.extra ?? [], - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Request Declined`, - }, - }); - } - - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; - } - } - - private async sendMediaAvailableEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - if ( - payload.notifyUser && - (payload.notifyUser.settings?.enableNotifications ?? true) - ) { - const email = new PreparedEmail(payload.notifyUser.settings?.pgpKey); - - await email.send({ - template: path.join( - __dirname, - '../../../templates/email/media-request' - ), - message: { - to: payload.notifyUser.email, - }, - locals: { - body: `The following ${ - payload.media?.mediaType === MediaType.TV ? 'series' : 'movie' - } you requested is now available!`, - mediaName: payload.subject, - mediaExtra: payload.extra ?? [], - imageUrl: payload.image, - timestamp: new Date().toTimeString(), - requestedBy: payload.request?.requestedBy.displayName, - actionUrl: applicationUrl - ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}` - : undefined, - applicationUrl, - applicationTitle, - requestType: `${ - payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie' - } Now Available`, - }, - }); - } - - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; - } - } - - private async sendTestEmail(payload: NotificationPayload) { - // This is getting main settings for the whole app - const { applicationUrl, applicationTitle } = getSettings().main; - try { - if (payload.notifyUser) { - const email = new PreparedEmail(payload.notifyUser.settings?.pgpKey); - - await email.send({ - template: path.join(__dirname, '../../../templates/email/test-email'), - message: { - to: payload.notifyUser.email, - }, - locals: { - body: payload.message, - applicationUrl, - applicationTitle, - }, - }); - } - - return true; - } catch (e) { - logger.error('Email notification failed to send', { - label: 'Notifications', - message: e.message, - }); - return false; - } + return undefined; } public async send( type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending email notification', { label: 'Notifications' }); + if (payload.notifyUser) { + // Send notification to the user who submitted the request + if ( + !payload.notifyUser.settings || + payload.notifyUser.settings.hasNotificationAgentEnabled( + NotificationAgentType.EMAIL + ) + ) { + logger.debug('Sending email notification', { + label: 'Notifications', + recipient: payload.notifyUser.displayName, + type: Notification[type], + subject: payload.subject, + }); - switch (type) { - case Notification.MEDIA_PENDING: - this.sendMediaRequestEmail(payload); - break; - case Notification.MEDIA_APPROVED: - this.sendMediaApprovedEmail(payload); - break; - case Notification.MEDIA_AUTO_APPROVED: - this.sendMediaAutoApprovedEmail(payload); - break; - case Notification.MEDIA_DECLINED: - this.sendMediaDeclinedEmail(payload); - break; - case Notification.MEDIA_AVAILABLE: - this.sendMediaAvailableEmail(payload); - break; - case Notification.MEDIA_FAILED: - this.sendMediaFailedEmail(payload); - break; - case Notification.TEST_NOTIFICATION: - this.sendTestEmail(payload); - break; + try { + const email = new PreparedEmail( + this.getSettings(), + payload.notifyUser.settings?.pgpKey + ); + await email.send( + this.buildMessage(type, payload, payload.notifyUser.email) + ); + } catch (e) { + logger.error('Error sending email notification', { + label: 'Notifications', + recipient: payload.notifyUser.displayName, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + }); + + return false; + } + } + } else { + // Send notifications to all users with the Manage Requests permission + const userRepository = getRepository(User); + const users = await userRepository.find(); + + await Promise.all( + users + .filter( + (user) => + user.hasPermission(Permission.MANAGE_REQUESTS) && + (!user.settings || + user.settings.hasNotificationAgentEnabled( + NotificationAgentType.EMAIL + )) + ) + .map(async (user) => { + logger.debug('Sending email notification', { + label: 'Notifications', + recipient: user.displayName, + type: Notification[type], + subject: payload.subject, + }); + + try { + const email = new PreparedEmail( + this.getSettings(), + user.settings?.pgpKey + ); + await email.send(this.buildMessage(type, payload, user.email)); + } catch (e) { + logger.error('Error sending email notification', { + label: 'Notifications', + recipient: user.displayName, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + }); + + return false; + } + }) + ); } return true; diff --git a/server/lib/notifications/agents/pushbullet.ts b/server/lib/notifications/agents/pushbullet.ts index f0c0f757..c43e9971 100644 --- a/server/lib/notifications/agents/pushbullet.ts +++ b/server/lib/notifications/agents/pushbullet.ts @@ -1,9 +1,9 @@ import axios from 'axios'; import { hasNotificationType, Notification } from '..'; +import { MediaType } from '../../../constants/media'; import logger from '../../../logger'; import { getSettings, NotificationAgentPushbullet } from '../../settings'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; -import { MediaType } from '../../../constants/media'; interface PushbulletPayload { title: string; @@ -136,7 +136,12 @@ class PushbulletAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending Pushbullet notification', { label: 'Notifications' }); + logger.debug('Sending Pushbullet notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); + try { const endpoint = 'https://api.pushbullet.com/v2/pushes'; @@ -162,8 +167,12 @@ class PushbulletAgent } catch (e) { logger.error('Error sending Pushbullet notification', { label: 'Notifications', - message: e.message, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + response: e.response.data, }); + return false; } } diff --git a/server/lib/notifications/agents/pushover.ts b/server/lib/notifications/agents/pushover.ts index 3b5d3f87..f9bff21c 100644 --- a/server/lib/notifications/agents/pushover.ts +++ b/server/lib/notifications/agents/pushover.ts @@ -1,9 +1,9 @@ import axios from 'axios'; import { hasNotificationType, Notification } from '..'; +import { MediaType } from '../../../constants/media'; import logger from '../../../logger'; import { getSettings, NotificationAgentPushover } from '../../settings'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; -import { MediaType } from '../../../constants/media'; interface PushoverPayload { token: string; @@ -160,7 +160,11 @@ class PushoverAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending Pushover notification', { label: 'Notifications' }); + logger.debug('Sending Pushover notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); try { const endpoint = 'https://api.pushover.net/1/messages.json'; @@ -189,8 +193,12 @@ class PushoverAgent } catch (e) { logger.error('Error sending Pushover notification', { label: 'Notifications', - message: e.message, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + response: e.response.data, }); + return false; } } diff --git a/server/lib/notifications/agents/slack.ts b/server/lib/notifications/agents/slack.ts index b5234785..f9fe46c9 100644 --- a/server/lib/notifications/agents/slack.ts +++ b/server/lib/notifications/agents/slack.ts @@ -1,9 +1,9 @@ import axios from 'axios'; import { hasNotificationType, Notification } from '..'; +import { MediaType } from '../../../constants/media'; import logger from '../../../logger'; import { getSettings, NotificationAgentSlack } from '../../settings'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; -import { MediaType } from '../../../constants/media'; interface EmbedField { type: 'plain_text' | 'mrkdwn'; @@ -67,9 +67,7 @@ class SlackAgent if (payload.request) { fields.push({ type: 'mrkdwn', - text: `*Requested By*\n${ - payload.request?.requestedBy.displayName ?? '' - }`, + text: `*Requested By*\n${payload.request.requestedBy.displayName}`, }); } @@ -235,7 +233,11 @@ class SlackAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending Slack notification', { label: 'Notifications' }); + logger.debug('Sending Slack notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); try { const webhookUrl = this.getSettings().options.webhookUrl; @@ -249,8 +251,12 @@ class SlackAgent } catch (e) { logger.error('Error sending Slack notification', { label: 'Notifications', - message: e.message, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + response: e.response.data, }); + return false; } } diff --git a/server/lib/notifications/agents/telegram.ts b/server/lib/notifications/agents/telegram.ts index 5fa4c518..894a7726 100644 --- a/server/lib/notifications/agents/telegram.ts +++ b/server/lib/notifications/agents/telegram.ts @@ -3,6 +3,7 @@ import { hasNotificationType, Notification } from '..'; import { MediaType } from '../../../constants/media'; import logger from '../../../logger'; import { getSettings, NotificationAgentTelegram } from '../../settings'; +import { NotificationAgentType } from '../agenttypes'; import { BaseAgent, NotificationAgent, NotificationPayload } from './agent'; interface TelegramMessagePayload { @@ -155,62 +156,98 @@ class TelegramAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending Telegram notification', { label: 'Notifications' }); + const endpoint = `${this.baseUrl}bot${this.getSettings().options.botAPI}/${ + payload.image ? 'sendPhoto' : 'sendMessage' + }`; + + // Send system notification try { - const endpoint = `${this.baseUrl}bot${ - this.getSettings().options.botAPI - }/${payload.image ? 'sendPhoto' : 'sendMessage'}`; + logger.debug('Sending Telegram notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); - // Send system notification - await (payload.image - ? axios.post(endpoint, { - photo: payload.image, - caption: this.buildMessage(type, payload), - parse_mode: 'MarkdownV2', - chat_id: `${this.getSettings().options.chatId}`, - disable_notification: this.getSettings().options.sendSilently, - } as TelegramPhotoPayload) - : axios.post(endpoint, { - text: this.buildMessage(type, payload), - parse_mode: 'MarkdownV2', - chat_id: `${this.getSettings().options.chatId}`, - disable_notification: this.getSettings().options.sendSilently, - } as TelegramMessagePayload)); - - // Send user notification - if ( - payload.notifyUser && - (payload.notifyUser.settings?.enableNotifications ?? true) && - payload.notifyUser.settings?.telegramChatId && - payload.notifyUser.settings?.telegramChatId !== - this.getSettings().options.chatId - ) { - await (payload.image - ? axios.post(endpoint, { + await axios.post( + endpoint, + payload.image + ? ({ photo: payload.image, caption: this.buildMessage(type, payload), parse_mode: 'MarkdownV2', - chat_id: `${payload.notifyUser.settings.telegramChatId}`, - disable_notification: - payload.notifyUser.settings.telegramSendSilently, + chat_id: this.getSettings().options.chatId, + disable_notification: this.getSettings().options.sendSilently, } as TelegramPhotoPayload) - : axios.post(endpoint, { + : ({ text: this.buildMessage(type, payload), parse_mode: 'MarkdownV2', - chat_id: `${payload.notifyUser.settings.telegramChatId}`, - disable_notification: - payload.notifyUser.settings.telegramSendSilently, - } as TelegramMessagePayload)); - } - - return true; + chat_id: `${this.getSettings().options.chatId}`, + disable_notification: this.getSettings().options.sendSilently, + } as TelegramMessagePayload) + ); } catch (e) { logger.error('Error sending Telegram notification', { label: 'Notifications', - message: e.message, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + response: e.response.data, }); return false; } + + if ( + payload.notifyUser && + payload.notifyUser.settings?.hasNotificationAgentEnabled( + NotificationAgentType.TELEGRAM + ) && + payload.notifyUser.settings?.telegramChatId && + payload.notifyUser.settings?.telegramChatId !== + this.getSettings().options.chatId + ) { + // Send notification to the user who submitted the request + logger.debug('Sending Telegram notification', { + label: 'Notifications', + recipient: payload.notifyUser.displayName, + type: Notification[type], + subject: payload.subject, + }); + + try { + await axios.post( + endpoint, + payload.image + ? ({ + photo: payload.image, + caption: this.buildMessage(type, payload), + parse_mode: 'MarkdownV2', + chat_id: payload.notifyUser.settings.telegramChatId, + disable_notification: + payload.notifyUser.settings.telegramSendSilently, + } as TelegramPhotoPayload) + : ({ + text: this.buildMessage(type, payload), + parse_mode: 'MarkdownV2', + chat_id: payload.notifyUser.settings.telegramChatId, + disable_notification: + payload.notifyUser.settings.telegramSendSilently, + } as TelegramMessagePayload) + ); + } catch (e) { + logger.error('Error sending Telegram notification', { + label: 'Notifications', + recipient: payload.notifyUser.displayName, + type: Notification[type], + subject: payload.subject, + errorMessage: e.message, + response: e.response.data, + }); + + return false; + } + } + + return true; } } diff --git a/server/lib/notifications/agents/webhook.ts b/server/lib/notifications/agents/webhook.ts index fa3058fe..7630cf44 100644 --- a/server/lib/notifications/agents/webhook.ts +++ b/server/lib/notifications/agents/webhook.ts @@ -30,6 +30,12 @@ const KeyMap: Record = { media_status4k: (payload) => payload.media?.status ? MediaStatus[payload.media?.status4k] : '', request_id: 'request.id', + requestedBy_username: 'request.requestedBy.displayName', + requestedBy_email: 'request.requestedBy.email', + requestedBy_avatar: 'request.requestedBy.avatar', + requestedBy_settings_discordId: 'request.requestedBy.settings.discordId', + requestedBy_settings_telegramChatId: + 'request.requestedBy.settings.telegramChatId', }; class WebhookAgent @@ -122,7 +128,12 @@ class WebhookAgent type: Notification, payload: NotificationPayload ): Promise { - logger.debug('Sending webhook notification', { label: 'Notifications' }); + logger.debug('Sending webhook notification', { + label: 'Notifications', + type: Notification[type], + subject: payload.subject, + }); + try { const { webhookUrl, authHeader } = this.getSettings().options; @@ -140,8 +151,12 @@ class WebhookAgent } catch (e) { logger.error('Error sending webhook notification', { label: 'Notifications', + type: Notification[type], + subject: payload.subject, errorMessage: e.message, + response: e.response.data, }); + return false; } } diff --git a/server/lib/notifications/agenttypes.ts b/server/lib/notifications/agenttypes.ts new file mode 100644 index 00000000..9e0d79aa --- /dev/null +++ b/server/lib/notifications/agenttypes.ts @@ -0,0 +1,16 @@ +export enum NotificationAgentType { + NONE = 0, + EMAIL = 2, + DISCORD = 4, + TELEGRAM = 8, + PUSHOVER = 16, + PUSHBULLET = 32, + SLACK = 64, +} + +export const hasNotificationAgentEnabled = ( + agent: NotificationAgentType, + value: number +): boolean => { + return !!(value & agent); +}; diff --git a/server/lib/notifications/index.ts b/server/lib/notifications/index.ts index 7d5b6800..f1f237f5 100644 --- a/server/lib/notifications/index.ts +++ b/server/lib/notifications/index.ts @@ -38,7 +38,7 @@ class NotificationManager { public registerAgents = (agents: NotificationAgent[]): void => { this.activeAgents = [...this.activeAgents, ...agents]; - logger.info('Registered Notification Agents', { label: 'Notifications' }); + logger.info('Registered notification agents', { label: 'Notifications' }); }; public sendNotification( @@ -46,8 +46,9 @@ class NotificationManager { payload: NotificationPayload ): void { const settings = getSettings().notifications; - logger.info(`Sending notification for ${Notification[type]}`, { + logger.info(`Sending notification(s) for ${Notification[type]}`, { label: 'Notifications', + subject: payload.subject, }); this.activeAgents.forEach((agent) => { if (settings.enabled && agent.shouldSend(type)) { diff --git a/server/lib/scanners/radarr/index.ts b/server/lib/scanners/radarr/index.ts index 74682cc5..f3573209 100644 --- a/server/lib/scanners/radarr/index.ts +++ b/server/lib/scanners/radarr/index.ts @@ -1,5 +1,5 @@ import { uniqWith } from 'lodash'; -import RadarrAPI, { RadarrMovie } from '../../../api/radarr'; +import RadarrAPI, { RadarrMovie } from '../../../api/servarr/radarr'; import { getSettings, RadarrSettings } from '../../settings'; import BaseScanner, { RunnableScanner, StatusBase } from '../baseScanner'; @@ -52,7 +52,7 @@ class RadarrScanner this.radarrApi = new RadarrAPI({ apiKey: server.apiKey, - url: RadarrAPI.buildRadarrUrl(server, '/api/v3'), + url: RadarrAPI.buildUrl(server, '/api/v3'), }); this.items = await this.radarrApi.getMovies(); diff --git a/server/lib/scanners/sonarr/index.ts b/server/lib/scanners/sonarr/index.ts index 4bc505fb..73500db9 100644 --- a/server/lib/scanners/sonarr/index.ts +++ b/server/lib/scanners/sonarr/index.ts @@ -1,6 +1,6 @@ import { uniqWith } from 'lodash'; import { getRepository } from 'typeorm'; -import SonarrAPI, { SonarrSeries } from '../../../api/sonarr'; +import SonarrAPI, { SonarrSeries } from '../../../api/servarr/sonarr'; import Media from '../../../entity/Media'; import { getSettings, SonarrSettings } from '../../settings'; import BaseScanner, { @@ -58,7 +58,7 @@ class SonarrScanner this.sonarrApi = new SonarrAPI({ apiKey: server.apiKey, - url: SonarrAPI.buildSonarrUrl(server, '/api/v3'), + url: SonarrAPI.buildUrl(server, '/api/v3'), }); this.items = await this.sonarrApi.getSeries(); diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 5809600f..bb82c7ef 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -30,7 +30,7 @@ export interface PlexSettings { libraries: Library[]; } -interface DVRSettings { +export interface DVRSettings { id: number; name: string; hostname: string; @@ -41,6 +41,7 @@ interface DVRSettings { activeProfileId: number; activeProfileName: string; activeDirectory: string; + tags: number[]; is4k: boolean; isDefault: boolean; externalUrl?: string; @@ -58,6 +59,7 @@ export interface SonarrSettings extends DVRSettings { activeAnimeDirectory?: string; activeAnimeLanguageProfileId?: number; activeLanguageProfileId?: number; + animeTags?: number[]; enableSeasonFolders: boolean; } @@ -295,7 +297,7 @@ class Settings { webhookUrl: '', authHeader: '', jsonPayload: - 'IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJzdWJqZWN0XCI6IFwie3tzdWJqZWN0fX1cIixcbiAgICBcIm1lc3NhZ2VcIjogXCJ7e21lc3NhZ2V9fVwiLFxuICAgIFwiaW1hZ2VcIjogXCJ7e2ltYWdlfX1cIixcbiAgICBcImVtYWlsXCI6IFwie3tub3RpZnl1c2VyX2VtYWlsfX1cIixcbiAgICBcInVzZXJuYW1lXCI6IFwie3tub3RpZnl1c2VyX3VzZXJuYW1lfX1cIixcbiAgICBcImF2YXRhclwiOiBcInt7bm90aWZ5dXNlcl9hdmF0YXJ9fVwiLFxuICAgIFwie3ttZWRpYX19XCI6IHtcbiAgICAgICAgXCJtZWRpYV90eXBlXCI6IFwie3ttZWRpYV90eXBlfX1cIixcbiAgICAgICAgXCJ0bWRiSWRcIjogXCJ7e21lZGlhX3RtZGJpZH19XCIsXG4gICAgICAgIFwiaW1kYklkXCI6IFwie3ttZWRpYV9pbWRiaWR9fVwiLFxuICAgICAgICBcInR2ZGJJZFwiOiBcInt7bWVkaWFfdHZkYmlkfX1cIixcbiAgICAgICAgXCJzdGF0dXNcIjogXCJ7e21lZGlhX3N0YXR1c319XCIsXG4gICAgICAgIFwic3RhdHVzNGtcIjogXCJ7e21lZGlhX3N0YXR1czRrfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i', + 'IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJzdWJqZWN0XCI6IFwie3tzdWJqZWN0fX1cIixcbiAgICBcIm1lc3NhZ2VcIjogXCJ7e21lc3NhZ2V9fVwiLFxuICAgIFwiaW1hZ2VcIjogXCJ7e2ltYWdlfX1cIixcbiAgICBcImVtYWlsXCI6IFwie3tub3RpZnl1c2VyX2VtYWlsfX1cIixcbiAgICBcInVzZXJuYW1lXCI6IFwie3tub3RpZnl1c2VyX3VzZXJuYW1lfX1cIixcbiAgICBcImF2YXRhclwiOiBcInt7bm90aWZ5dXNlcl9hdmF0YXJ9fVwiLFxuICAgIFwie3ttZWRpYX19XCI6IHtcbiAgICAgICAgXCJtZWRpYV90eXBlXCI6IFwie3ttZWRpYV90eXBlfX1cIixcbiAgICAgICAgXCJ0bWRiSWRcIjogXCJ7e21lZGlhX3RtZGJpZH19XCIsXG4gICAgICAgIFwiaW1kYklkXCI6IFwie3ttZWRpYV9pbWRiaWR9fVwiLFxuICAgICAgICBcInR2ZGJJZFwiOiBcInt7bWVkaWFfdHZkYmlkfX1cIixcbiAgICAgICAgXCJzdGF0dXNcIjogXCJ7e21lZGlhX3N0YXR1c319XCIsXG4gICAgICAgIFwic3RhdHVzNGtcIjogXCJ7e21lZGlhX3N0YXR1czRrfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW10sXG4gICAgXCJ7e3JlcXVlc3R9fVwiOiB7XG4gICAgICAgIFwicmVxdWVzdF9pZFwiOiBcInt7cmVxdWVzdF9pZH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfZW1haWxcIjogXCJ7e3JlcXVlc3RlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV91c2VybmFtZVwiOiBcInt7cmVxdWVzdGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2F2YXRhclwiOiBcInt7cmVxdWVzdGVkQnlfYXZhdGFyfX1cIlxuICAgIH1cbn0i', }, }, }, diff --git a/server/migration/1617624225464-CreateTagsFieldonMediaRequest.ts b/server/migration/1617624225464-CreateTagsFieldonMediaRequest.ts new file mode 100644 index 00000000..c8bd6dd4 --- /dev/null +++ b/server/migration/1617624225464-CreateTagsFieldonMediaRequest.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class CreateTagsFieldonMediaRequest1617624225464 + implements MigrationInterface { + name = 'CreateTagsFieldonMediaRequest1617624225464'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "temporary_media_request" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "status" integer NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "updatedAt" datetime NOT NULL DEFAULT (datetime('now')), "type" varchar NOT NULL, "mediaId" integer, "requestedById" integer, "modifiedById" integer, "is4k" boolean NOT NULL DEFAULT (0), "serverId" integer, "profileId" integer, "rootFolder" varchar, "languageProfileId" integer, "tags" text, CONSTRAINT "FK_f4fc4efa14c3ba2b29c4525fa15" FOREIGN KEY ("modifiedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_6997bee94720f1ecb7f31137095" FOREIGN KEY ("requestedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_a1aa713f41c99e9d10c48da75a0" FOREIGN KEY ("mediaId") REFERENCES "media" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ); + await queryRunner.query( + `INSERT INTO "temporary_media_request"("id", "status", "createdAt", "updatedAt", "type", "mediaId", "requestedById", "modifiedById", "is4k", "serverId", "profileId", "rootFolder", "languageProfileId") SELECT "id", "status", "createdAt", "updatedAt", "type", "mediaId", "requestedById", "modifiedById", "is4k", "serverId", "profileId", "rootFolder", "languageProfileId" FROM "media_request"` + ); + await queryRunner.query(`DROP TABLE "media_request"`); + await queryRunner.query( + `ALTER TABLE "temporary_media_request" RENAME TO "media_request"` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "media_request" RENAME TO "temporary_media_request"` + ); + await queryRunner.query( + `CREATE TABLE "media_request" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "status" integer NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "updatedAt" datetime NOT NULL DEFAULT (datetime('now')), "type" varchar NOT NULL, "mediaId" integer, "requestedById" integer, "modifiedById" integer, "is4k" boolean NOT NULL DEFAULT (0), "serverId" integer, "profileId" integer, "rootFolder" varchar, "languageProfileId" integer, CONSTRAINT "FK_f4fc4efa14c3ba2b29c4525fa15" FOREIGN KEY ("modifiedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_6997bee94720f1ecb7f31137095" FOREIGN KEY ("requestedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_a1aa713f41c99e9d10c48da75a0" FOREIGN KEY ("mediaId") REFERENCES "media" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ); + await queryRunner.query( + `INSERT INTO "media_request"("id", "status", "createdAt", "updatedAt", "type", "mediaId", "requestedById", "modifiedById", "is4k", "serverId", "profileId", "rootFolder", "languageProfileId") SELECT "id", "status", "createdAt", "updatedAt", "type", "mediaId", "requestedById", "modifiedById", "is4k", "serverId", "profileId", "rootFolder", "languageProfileId" FROM "temporary_media_request"` + ); + await queryRunner.query(`DROP TABLE "temporary_media_request"`); + } +} diff --git a/server/migration/1617730837489-AddUserSettingsNotificationAgentsField.ts b/server/migration/1617730837489-AddUserSettingsNotificationAgentsField.ts new file mode 100644 index 00000000..86a52c08 --- /dev/null +++ b/server/migration/1617730837489-AddUserSettingsNotificationAgentsField.ts @@ -0,0 +1,52 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddUserSettingsNotificationAgentsField1617730837489 + implements MigrationInterface { + name = 'AddUserSettingsNotificationAgentsField1617730837489'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationAgents" NOT NULL DEFAULT (2), "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" 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", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey") SELECT "id", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey" FROM "user_settings"` + ); + await queryRunner.query(`DROP TABLE "user_settings"`); + await queryRunner.query( + `ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"` + ); + await queryRunner.query( + `CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationAgents" integer NOT NULL DEFAULT (2), "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" 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", "notificationAgents", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey") SELECT "id", "notificationAgents", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey" 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 { + 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, "notificationAgents" NOT NULL DEFAULT (2), "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" 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 "user_settings"("id", "notificationAgents", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey") SELECT "id", "notificationAgents", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey" FROM "temporary_user_settings"` + ); + await queryRunner.query(`DROP TABLE "temporary_user_settings"`); + 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, "enableNotifications" boolean NOT NULL DEFAULT (1), "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" 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 "user_settings"("id", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey") SELECT "id", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey" FROM "temporary_user_settings"` + ); + await queryRunner.query(`DROP TABLE "temporary_user_settings"`); + } +} diff --git a/server/routes/index.ts b/server/routes/index.ts index af9537db..d9e2342b 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -1,33 +1,75 @@ import { Router } from 'express'; -import user from './user'; -import authRoutes from './auth'; -import { checkUser, isAuthenticated } from '../middleware/auth'; -import settingsRoutes from './settings'; +import GithubAPI from '../api/github'; +import TheMovieDb from '../api/themoviedb'; +import { StatusResponse } from '../interfaces/api/settingsInterfaces'; import { Permission } from '../lib/permissions'; import { getSettings } from '../lib/settings'; -import searchRoutes from './search'; -import discoverRoutes from './discover'; -import requestRoutes from './request'; -import movieRoutes from './movie'; -import tvRoutes from './tv'; -import mediaRoutes from './media'; -import personRoutes from './person'; -import collectionRoutes from './collection'; -import { getAppVersion, getCommitTag } from '../utils/appVersion'; -import serviceRoutes from './service'; -import { appDataStatus, appDataPath } from '../utils/appDataVolume'; -import TheMovieDb from '../api/themoviedb'; +import { checkUser, isAuthenticated } from '../middleware/auth'; import { mapProductionCompany } from '../models/Movie'; import { mapNetwork } from '../models/Tv'; +import { appDataPath, appDataStatus } from '../utils/appDataVolume'; +import { getAppVersion, getCommitTag } from '../utils/appVersion'; +import authRoutes from './auth'; +import collectionRoutes from './collection'; +import discoverRoutes from './discover'; +import mediaRoutes from './media'; +import movieRoutes from './movie'; +import personRoutes from './person'; +import requestRoutes from './request'; +import searchRoutes from './search'; +import serviceRoutes from './service'; +import settingsRoutes from './settings'; +import tvRoutes from './tv'; +import user from './user'; const router = Router(); router.use(checkUser); -router.get('/status', (req, res) => { +router.get('/status', async (req, res) => { + const githubApi = new GithubAPI(); + + const currentVersion = getAppVersion(); + const commitTag = getCommitTag(); + let updateAvailable = false; + let commitsBehind = 0; + + if (currentVersion.startsWith('develop-') && commitTag !== 'local') { + const commits = await githubApi.getOverseerrCommits(); + + if (commits.length) { + const filteredCommits = commits.filter( + (commit) => !commit.commit.message.includes('[skip ci]') + ); + if (filteredCommits[0].sha !== commitTag) { + updateAvailable = true; + } + + const commitIndex = filteredCommits.findIndex( + (commit) => commit.sha === commitTag + ); + + if (updateAvailable) { + commitsBehind = commitIndex; + } + } + } else if (commitTag !== 'local') { + const releases = await githubApi.getOverseerrReleases(); + + if (releases.length) { + const latestVersion = releases[0]; + + if (latestVersion.name !== currentVersion) { + updateAvailable = true; + } + } + } + return res.status(200).json({ version: getAppVersion(), commitTag: getCommitTag(), + updateAvailable, + commitsBehind, }); }); @@ -39,7 +81,7 @@ router.get('/status/appdata', (_req, res) => { }); router.use('/user', isAuthenticated(), user); -router.get('/settings/public', (_req, res) => { +router.get('/settings/public', async (_req, res) => { const settings = getSettings(); return res.status(200).json(settings.fullPublicSettings); diff --git a/server/routes/request.ts b/server/routes/request.ts index b7598f4e..6ad4ac05 100644 --- a/server/routes/request.ts +++ b/server/routes/request.ts @@ -278,6 +278,7 @@ requestRoutes.post( serverId: req.body.serverId, profileId: req.body.profileId, rootFolder: req.body.rootFolder, + tags: req.body.tags, }); await requestRepository.save(request); @@ -356,6 +357,7 @@ requestRoutes.post( profileId: req.body.profileId, rootFolder: req.body.rootFolder, languageProfileId: req.body.languageProfileId, + tags: req.body.tags, seasons: finalSeasons.map( (sn) => new SeasonRequest({ @@ -497,6 +499,7 @@ requestRoutes.put<{ requestId: string }>( request.serverId = req.body.serverId; request.profileId = req.body.profileId; request.rootFolder = req.body.rootFolder; + request.tags = req.body.tags; request.requestedBy = requestUser as User; requestRepository.save(request); @@ -505,6 +508,8 @@ requestRoutes.put<{ requestId: string }>( request.serverId = req.body.serverId; request.profileId = req.body.profileId; request.rootFolder = req.body.rootFolder; + request.languageProfileId = req.body.languageProfileId; + request.tags = req.body.tags; request.requestedBy = requestUser as User; const requestedSeasons = req.body.seasons as number[] | undefined; diff --git a/server/routes/service.ts b/server/routes/service.ts index 5e6dccc8..51bbc4e3 100644 --- a/server/routes/service.ts +++ b/server/routes/service.ts @@ -1,12 +1,12 @@ import { Router } from 'express'; -import RadarrAPI from '../api/radarr'; -import SonarrAPI from '../api/sonarr'; +import RadarrAPI from '../api/servarr/radarr'; +import SonarrAPI from '../api/servarr/sonarr'; +import TheMovieDb from '../api/themoviedb'; import { ServiceCommonServer, ServiceCommonServerWithDetails, } from '../interfaces/api/serviceInterfaces'; import { getSettings } from '../lib/settings'; -import TheMovieDb from '../api/themoviedb'; import logger from '../logger'; const serviceRoutes = Router(); @@ -22,6 +22,7 @@ serviceRoutes.get('/radarr', async (req, res) => { isDefault: radarr.isDefault, activeDirectory: radarr.activeDirectory, activeProfileId: radarr.activeProfileId, + activeTags: radarr.tags ?? [], }) ); @@ -46,11 +47,12 @@ serviceRoutes.get<{ radarrId: string }>( const radarr = new RadarrAPI({ apiKey: radarrSettings.apiKey, - url: RadarrAPI.buildRadarrUrl(radarrSettings, '/api/v3'), + url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'), }); const profiles = await radarr.getProfiles(); const rootFolders = await radarr.getRootFolders(); + const tags = await radarr.getTags(); return res.status(200).json({ server: { @@ -60,6 +62,7 @@ serviceRoutes.get<{ radarrId: string }>( isDefault: radarrSettings.isDefault, activeDirectory: radarrSettings.activeDirectory, activeProfileId: radarrSettings.activeProfileId, + activeTags: radarrSettings.tags, }, profiles: profiles.map((profile) => ({ id: profile.id, @@ -71,6 +74,7 @@ serviceRoutes.get<{ radarrId: string }>( path: folder.path, totalSpace: folder.totalSpace, })), + tags, } as ServiceCommonServerWithDetails); } ); @@ -90,6 +94,7 @@ serviceRoutes.get('/sonarr', async (req, res) => { activeAnimeDirectory: sonarr.activeAnimeDirectory, activeLanguageProfileId: sonarr.activeLanguageProfileId, activeAnimeLanguageProfileId: sonarr.activeAnimeLanguageProfileId, + activeTags: [], }) ); @@ -114,13 +119,14 @@ serviceRoutes.get<{ sonarrId: string }>( const sonarr = new SonarrAPI({ apiKey: sonarrSettings.apiKey, - url: SonarrAPI.buildSonarrUrl(sonarrSettings, '/api/v3'), + url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'), }); try { const profiles = await sonarr.getProfiles(); const rootFolders = await sonarr.getRootFolders(); const languageProfiles = await sonarr.getLanguageProfiles(); + const tags = await sonarr.getTags(); return res.status(200).json({ server: { @@ -135,6 +141,8 @@ serviceRoutes.get<{ sonarrId: string }>( activeLanguageProfileId: sonarrSettings.activeLanguageProfileId, activeAnimeLanguageProfileId: sonarrSettings.activeAnimeLanguageProfileId, + activeTags: sonarrSettings.tags, + activeAnimeTags: sonarrSettings.animeTags, }, profiles: profiles.map((profile) => ({ id: profile.id, @@ -147,6 +155,7 @@ serviceRoutes.get<{ sonarrId: string }>( totalSpace: folder.totalSpace, })), languageProfiles: languageProfiles, + tags, } as ServiceCommonServerWithDetails); } catch (e) { next({ status: 500, message: e.message }); diff --git a/server/routes/settings/index.ts b/server/routes/settings/index.ts index c17e3e13..719e8c9f 100644 --- a/server/routes/settings/index.ts +++ b/server/routes/settings/index.ts @@ -113,7 +113,6 @@ settingsRoutes.post('/plex', async (req, res, next) => { settingsRoutes.get('/plex/devices/servers', async (req, res, next) => { const userRepository = getRepository(User); - const regexp = /(http(s?):\/\/)(.*)(:[0-9]*)/; try { const admin = await userRepository.findOneOrFail({ select: ['id', 'plexToken'], @@ -126,40 +125,32 @@ settingsRoutes.get('/plex/devices/servers', async (req, res, next) => { return device.provides.includes('server') && device.owned; }); const settings = getSettings(); + if (devices) { await Promise.all( devices.map(async (device) => { await Promise.all( device.connection.map(async (connection) => { - connection.host = connection.uri.replace(regexp, '$3'); - let msg: - | { status: number; message: string } - | undefined = undefined; const plexDeviceSettings = { ...settings.plex, - ip: connection.host, + ip: connection.address, port: connection.port, - useSsl: connection.protocol === 'https' ? true : false, + useSsl: !connection.local && connection.protocol === 'https', }; const plexClient = new PlexAPI({ plexToken: admin.plexToken, plexSettings: plexDeviceSettings, timeout: 5000, }); + try { await plexClient.getStatus(); - msg = { - status: 200, - message: 'OK', - }; + connection.status = 200; + connection.message = 'OK'; } catch (e) { - msg = { - status: 500, - message: e.message, - }; + connection.status = 500; + connection.message = e.message; } - connection.status = msg?.status; - connection.message = msg?.message; }) ); }) diff --git a/server/routes/settings/notifications.ts b/server/routes/settings/notifications.ts index fbf1ce1e..739b3981 100644 --- a/server/routes/settings/notifications.ts +++ b/server/routes/settings/notifications.ts @@ -1,36 +1,16 @@ import { Router } from 'express'; -import { getSettings } from '../../lib/settings'; import { Notification } from '../../lib/notifications'; import DiscordAgent from '../../lib/notifications/agents/discord'; import EmailAgent from '../../lib/notifications/agents/email'; +import PushbulletAgent from '../../lib/notifications/agents/pushbullet'; +import PushoverAgent from '../../lib/notifications/agents/pushover'; import SlackAgent from '../../lib/notifications/agents/slack'; import TelegramAgent from '../../lib/notifications/agents/telegram'; -import PushoverAgent from '../../lib/notifications/agents/pushover'; import WebhookAgent from '../../lib/notifications/agents/webhook'; -import PushbulletAgent from '../../lib/notifications/agents/pushbullet'; +import { getSettings } from '../../lib/settings'; const notificationRoutes = Router(); -notificationRoutes.get('/', (_req, res) => { - const settings = getSettings().notifications; - return res.status(200).json({ - enabled: settings.enabled, - }); -}); - -notificationRoutes.post('/', (req, res) => { - const settings = getSettings(); - - Object.assign(settings.notifications, { - enabled: req.body.enabled, - }); - settings.save(); - - return res.status(200).json({ - enabled: settings.notifications.enabled, - }); -}); - notificationRoutes.get('/discord', (_req, res) => { const settings = getSettings(); diff --git a/server/routes/settings/radarr.ts b/server/routes/settings/radarr.ts index 1e17a475..d250ea29 100644 --- a/server/routes/settings/radarr.ts +++ b/server/routes/settings/radarr.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import RadarrAPI from '../../api/radarr'; +import RadarrAPI from '../../api/servarr/radarr'; import { getSettings, RadarrSettings } from '../../lib/settings'; import logger from '../../logger'; @@ -35,15 +35,20 @@ radarrRoutes.post('/', (req, res) => { return res.status(201).json(newRadarr); }); -radarrRoutes.post('/test', async (req, res, next) => { +radarrRoutes.post< + undefined, + Record, + RadarrSettings & { tagLabel?: string } +>('/test', async (req, res, next) => { try { const radarr = new RadarrAPI({ apiKey: req.body.apiKey, - url: RadarrAPI.buildRadarrUrl(req.body, '/api/v3'), + url: RadarrAPI.buildUrl(req.body, '/api/v3'), }); const profiles = await radarr.getProfiles(); const folders = await radarr.getRootFolders(); + const tags = await radarr.getTags(); return res.status(200).json({ profiles, @@ -51,6 +56,7 @@ radarrRoutes.post('/test', async (req, res, next) => { id: folder.id, path: folder.path, })), + tags, }); } catch (e) { logger.error('Failed to test Radarr', { @@ -62,40 +68,41 @@ radarrRoutes.post('/test', async (req, res, next) => { } }); -radarrRoutes.put<{ id: string }>('/:id', (req, res) => { - const settings = getSettings(); +radarrRoutes.put<{ id: string }, RadarrSettings, RadarrSettings>( + '/:id', + (req, res, next) => { + const settings = getSettings(); - const radarrIndex = settings.radarr.findIndex( - (r) => r.id === Number(req.params.id) - ); + const radarrIndex = settings.radarr.findIndex( + (r) => r.id === Number(req.params.id) + ); - if (radarrIndex === -1) { - return res - .status(404) - .json({ status: '404', message: 'Settings instance not found' }); + if (radarrIndex === -1) { + return next({ status: '404', message: 'Settings instance not found' }); + } + + // If we are setting this as the default, clear any previous defaults for the same type first + // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true + // and are the default + if (req.body.isDefault) { + settings.radarr + .filter((radarrInstance) => radarrInstance.is4k === req.body.is4k) + .forEach((radarrInstance) => { + radarrInstance.isDefault = false; + }); + } + + settings.radarr[radarrIndex] = { + ...req.body, + id: Number(req.params.id), + } as RadarrSettings; + settings.save(); + + return res.status(200).json(settings.radarr[radarrIndex]); } +); - // If we are setting this as the default, clear any previous defaults for the same type first - // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true - // and are the default - if (req.body.isDefault) { - settings.radarr - .filter((radarrInstance) => radarrInstance.is4k === req.body.is4k) - .forEach((radarrInstance) => { - radarrInstance.isDefault = false; - }); - } - - settings.radarr[radarrIndex] = { - ...req.body, - id: Number(req.params.id), - } as RadarrSettings; - settings.save(); - - return res.status(200).json(settings.radarr[radarrIndex]); -}); - -radarrRoutes.get<{ id: string }>('/:id/profiles', async (req, res) => { +radarrRoutes.get<{ id: string }>('/:id/profiles', async (req, res, next) => { const settings = getSettings(); const radarrSettings = settings.radarr.find( @@ -103,14 +110,12 @@ radarrRoutes.get<{ id: string }>('/:id/profiles', async (req, res) => { ); if (!radarrSettings) { - return res - .status(404) - .json({ status: '404', message: 'Settings instance not found' }); + return next({ status: '404', message: 'Settings instance not found' }); } const radarr = new RadarrAPI({ apiKey: radarrSettings.apiKey, - url: RadarrAPI.buildRadarrUrl(radarrSettings, '/api/v3'), + url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'), }); const profiles = await radarr.getProfiles(); @@ -123,7 +128,7 @@ radarrRoutes.get<{ id: string }>('/:id/profiles', async (req, res) => { ); }); -radarrRoutes.delete<{ id: string }>('/:id', (req, res) => { +radarrRoutes.delete<{ id: string }>('/:id', (req, res, next) => { const settings = getSettings(); const radarrIndex = settings.radarr.findIndex( @@ -131,9 +136,7 @@ radarrRoutes.delete<{ id: string }>('/:id', (req, res) => { ); if (radarrIndex === -1) { - return res - .status(404) - .json({ status: '404', message: 'Settings instance not found' }); + return next({ status: '404', message: 'Settings instance not found' }); } const removed = settings.radarr.splice(radarrIndex, 1); diff --git a/server/routes/settings/sonarr.ts b/server/routes/settings/sonarr.ts index d9bbe3c2..4f63ebb3 100644 --- a/server/routes/settings/sonarr.ts +++ b/server/routes/settings/sonarr.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import SonarrAPI from '../../api/sonarr'; +import SonarrAPI from '../../api/servarr/sonarr'; import { getSettings, SonarrSettings } from '../../lib/settings'; import logger from '../../logger'; @@ -39,12 +39,13 @@ sonarrRoutes.post('/test', async (req, res, next) => { try { const sonarr = new SonarrAPI({ apiKey: req.body.apiKey, - url: SonarrAPI.buildSonarrUrl(req.body, '/api/v3'), + url: SonarrAPI.buildUrl(req.body, '/api/v3'), }); const profiles = await sonarr.getProfiles(); const folders = await sonarr.getRootFolders(); const languageProfiles = await sonarr.getLanguageProfiles(); + const tags = await sonarr.getTags(); return res.status(200).json({ profiles, @@ -53,6 +54,7 @@ sonarrRoutes.post('/test', async (req, res, next) => { path: folder.path, })), languageProfiles, + tags, }); } catch (e) { logger.error('Failed to test Sonarr', { diff --git a/server/routes/user/index.ts b/server/routes/user/index.ts index 2ddc700f..0c904691 100644 --- a/server/routes/user/index.ts +++ b/server/routes/user/index.ts @@ -281,7 +281,7 @@ router.delete<{ id: string }>( }); } - if (user.hasPermission(Permission.ADMIN)) { + if (user.hasPermission(Permission.ADMIN) && req.user?.id !== 1) { return next({ status: 405, message: 'You cannot delete users with administrative privileges.', diff --git a/server/routes/user/usersettings.ts b/server/routes/user/usersettings.ts index 693c228e..f85ef179 100644 --- a/server/routes/user/usersettings.ts +++ b/server/routes/user/usersettings.ts @@ -7,6 +7,7 @@ import { UserSettingsGeneralResponse, UserSettingsNotificationsResponse, } from '../../interfaces/api/userSettingsInterfaces'; +import { NotificationAgentType } from '../../lib/notifications/agenttypes'; import { Permission } from '../../lib/permissions'; import { getSettings } from '../../lib/settings'; import logger from '../../logger'; @@ -242,13 +243,17 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>( } return res.status(200).json({ - enableNotifications: user.settings?.enableNotifications ?? true, + notificationAgents: + user.settings?.notificationAgents ?? NotificationAgentType.EMAIL, + emailEnabled: settings?.notifications.agents.email.enabled, + pgpKey: user.settings?.pgpKey, + discordEnabled: settings?.notifications.agents.discord.enabled, + discordId: user.settings?.discordId, + telegramEnabled: settings?.notifications.agents.telegram.enabled, telegramBotUsername: settings?.notifications.agents.telegram.options.botUsername, - discordId: user.settings?.discordId, telegramChatId: user.settings?.telegramChatId, telegramSendSilently: user?.settings?.telegramSendSilently, - pgpKey: user?.settings?.pgpKey, }); } catch (e) { next({ status: 500, message: e.message }); @@ -256,60 +261,62 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>( } ); -userSettingsRoutes.post< - { id: string }, - UserSettingsNotificationsResponse, - UserSettingsNotificationsResponse ->('/notifications', isOwnProfileOrAdmin(), async (req, res, next) => { - const userRepository = getRepository(User); +userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>( + '/notifications', + isOwnProfileOrAdmin(), + async (req, res, next) => { + const userRepository = getRepository(User); - try { - const user = await userRepository.findOne({ - where: { id: Number(req.params.id) }, - }); - - if (!user) { - return next({ status: 404, message: 'User not found.' }); - } - - // "Owner" user settings cannot be modified by other users - if (user.id === 1 && req.user?.id !== 1) { - return next({ - status: 403, - message: "You do not have permission to modify this user's settings.", + try { + const user = await userRepository.findOne({ + where: { id: Number(req.params.id) }, }); - } - if (!user.settings) { - user.settings = new UserSettings({ - user: req.user, - enableNotifications: req.body.enableNotifications, - discordId: req.body.discordId, - telegramChatId: req.body.telegramChatId, - telegramSendSilently: req.body.telegramSendSilently, - pgpKey: req.body.pgpKey, + if (!user) { + return next({ status: 404, message: 'User not found.' }); + } + + // "Owner" user settings cannot be modified by other users + if (user.id === 1 && req.user?.id !== 1) { + return next({ + status: 403, + message: "You do not have permission to modify this user's settings.", + }); + } + + if (!user.settings) { + user.settings = new UserSettings({ + user: req.user, + notificationAgents: + req.body.notificationAgents ?? NotificationAgentType.EMAIL, + pgpKey: req.body.pgpKey, + discordId: req.body.discordId, + telegramChatId: req.body.telegramChatId, + telegramSendSilently: req.body.telegramSendSilently, + }); + } else { + user.settings.notificationAgents = + req.body.notificationAgents ?? NotificationAgentType.EMAIL; + user.settings.pgpKey = req.body.pgpKey; + user.settings.discordId = req.body.discordId; + user.settings.telegramChatId = req.body.telegramChatId; + user.settings.telegramSendSilently = req.body.telegramSendSilently; + } + + userRepository.save(user); + + return res.status(200).json({ + notificationAgents: user.settings?.notificationAgents, + pgpKey: user.settings?.pgpKey, + discordId: user.settings?.discordId, + telegramChatId: user.settings?.telegramChatId, + telegramSendSilently: user?.settings?.telegramSendSilently, }); - } else { - user.settings.enableNotifications = req.body.enableNotifications; - user.settings.discordId = req.body.discordId; - user.settings.telegramChatId = req.body.telegramChatId; - user.settings.telegramSendSilently = req.body.telegramSendSilently; - user.settings.pgpKey = req.body.pgpKey; + } catch (e) { + next({ status: 500, message: e.message }); } - - userRepository.save(user); - - return res.status(200).json({ - enableNotifications: user.settings.enableNotifications, - discordId: user.settings.discordId, - telegramChatId: user.settings.telegramChatId, - telegramSendSilently: user.settings.telegramSendSilently, - pgpKey: user.settings.pgpKey, - }); - } catch (e) { - next({ status: 500, message: e.message }); } -}); +); userSettingsRoutes.get<{ id: string }, { permissions?: number }>( '/permissions', diff --git a/server/templates/email/generatedpassword/html.pug b/server/templates/email/generatedpassword/html.pug index 1fa4713f..b9bc2a2e 100644 --- a/server/templates/email/generatedpassword/html.pug +++ b/server/templates/email/generatedpassword/html.pug @@ -42,7 +42,6 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') table(style='width: 100%' width='100%' cellpadding='0' cellspacing='0' role='presentation') tr td(align='center' style='\ - font-size: 16px;\ padding-top: 25px;\ padding-bottom: 25px;\ text-align: center;\ @@ -50,7 +49,7 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') a(href=applicationUrl style='\ text-shadow: 0 1px 0 #ffffff;\ font-weight: 700;\ - font-size: 16px;\ + font-size: 24px;\ color: #a8aaaf;\ text-decoration: none;\ ') diff --git a/server/templates/email/resetpassword/html.pug b/server/templates/email/resetpassword/html.pug index f7c8bb08..718a0495 100644 --- a/server/templates/email/resetpassword/html.pug +++ b/server/templates/email/resetpassword/html.pug @@ -42,7 +42,6 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') table(style='width: 100%' width='100%' cellpadding='0' cellspacing='0' role='presentation') tr td(align='center' style='\ - font-size: 16px;\ padding-top: 25px;\ padding-bottom: 25px;\ text-align: center;\ @@ -50,7 +49,7 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') a(href=applicationUrl style='\ text-shadow: 0 1px 0 #ffffff;\ font-weight: 700;\ - font-size: 16px;\ + font-size: 24px;\ color: #a8aaaf;\ text-decoration: none;\ ') diff --git a/server/templates/email/test-email/html.pug b/server/templates/email/test-email/html.pug index b4abfebb..f1b21b36 100644 --- a/server/templates/email/test-email/html.pug +++ b/server/templates/email/test-email/html.pug @@ -42,7 +42,6 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') table(style='width: 100%' width='100%' cellpadding='0' cellspacing='0' role='presentation') tr td(align='center' style='\ - font-size: 16px;\ padding-top: 25px;\ padding-bottom: 25px;\ text-align: center;\ @@ -50,7 +49,7 @@ div(role='article' aria-roledescription='email' aria-label='' lang='en') a(href=applicationUrl style='\ text-shadow: 0 1px 0 #ffffff;\ font-weight: 700;\ - font-size: 16px;\ + font-size: 24px;\ color: #a8aaaf;\ text-decoration: none;\ ') diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index a83561a0..0d73f8ad 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -11,9 +11,9 @@ confinement: strict parts: overseerr: plugin: nodejs - nodejs-version: "14.16.0" + nodejs-version: "14.16.1" nodejs-package-manager: "yarn" - nodejs-yarn-version: v1.22.5 + nodejs-yarn-version: v1.22.10 build-packages: - git - on arm64: diff --git a/src/components/AppDataWarning/index.tsx b/src/components/AppDataWarning/index.tsx index 3023db81..fce97bd5 100644 --- a/src/components/AppDataWarning/index.tsx +++ b/src/components/AppDataWarning/index.tsx @@ -4,7 +4,6 @@ import useSWR from 'swr'; import Alert from '../Common/Alert'; const messages = defineMessages({ - dockerVolumeMissing: 'Docker Volume Mount Missing', dockerVolumeMissingDescription: 'The {appDataPath} volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.', }); @@ -26,14 +25,14 @@ const AppDataWarning: React.FC = () => { return ( <> {!data.appData && ( - - {intl.formatMessage(messages.dockerVolumeMissingDescription, { + {msg}; }, appDataPath: data.appDataPath, })} - + /> )} ); diff --git a/src/components/Common/List/index.tsx b/src/components/Common/List/index.tsx index 689fba5c..7a893708 100644 --- a/src/components/Common/List/index.tsx +++ b/src/components/Common/List/index.tsx @@ -3,15 +3,16 @@ import { withProperties } from '../../../utils/typeHelpers'; interface ListItemProps { title: string; + className?: string; } -const ListItem: React.FC = ({ title, children }) => { +const ListItem: React.FC = ({ title, className, children }) => { return (
{title}
- {children} + {children}
diff --git a/src/components/Common/SettingsTabs/index.tsx b/src/components/Common/SettingsTabs/index.tsx new file mode 100644 index 00000000..2e47b418 --- /dev/null +++ b/src/components/Common/SettingsTabs/index.tsx @@ -0,0 +1,173 @@ +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import React from 'react'; +import { hasPermission, Permission } from '../../../../server/lib/permissions'; +import { useUser } from '../../../hooks/useUser'; + +export interface SettingsRoute { + text: string; + content?: React.ReactNode; + route: string; + regex: RegExp; + requiredPermission?: Permission | Permission[]; + permissionType?: { type: 'and' | 'or' }; + hidden?: boolean; +} + +const SettingsLink: React.FC<{ + tabType: 'default' | 'button'; + currentPath: string; + route: string; + regex: RegExp; + hidden?: boolean; + isMobile?: boolean; +}> = ({ + children, + tabType, + currentPath, + route, + regex, + hidden = false, + isMobile = false, +}) => { + if (hidden) { + return null; + } + + if (isMobile) { + return ; + } + + let linkClasses = + 'px-1 py-4 ml-8 text-sm font-medium leading-5 transition duration-300 border-b-2 border-transparent whitespace-nowrap first:ml-0'; + let activeLinkColor = 'text-indigo-500 border-indigo-600'; + let inactiveLinkColor = + 'text-gray-500 border-transparent hover:text-gray-300 hover:border-gray-400 focus:text-gray-300 focus:border-gray-400'; + + if (tabType === 'button') { + linkClasses = + 'px-3 py-2 ml-8 text-sm font-medium transition duration-300 rounded-md whitespace-nowrap first:ml-0'; + activeLinkColor = 'bg-indigo-700'; + inactiveLinkColor = 'bg-gray-800 hover:bg-gray-700 focus:bg-gray-700'; + } + + return ( + + + {children} + + + ); +}; + +const SettingsTabs: React.FC<{ + tabType?: 'default' | 'button'; + settingsRoutes: SettingsRoute[]; +}> = ({ tabType = 'default', settingsRoutes }) => { + const router = useRouter(); + const { user: currentUser } = useUser(); + + return ( + <> +
+ + +
+ {tabType === 'button' ? ( +
+ +
+ ) : ( +
+
+ +
+
+ )} + + ); +}; + +export default SettingsTabs; diff --git a/src/components/Discover/index.tsx b/src/components/Discover/index.tsx index 9a4d05c8..8560a535 100644 --- a/src/components/Discover/index.tsx +++ b/src/components/Discover/index.tsx @@ -21,7 +21,7 @@ const messages = defineMessages({ populartv: 'Popular Series', upcomingtv: 'Upcoming Series', recentlyAdded: 'Recently Added', - nopending: 'No Pending Requests', + noRequests: 'No requests.', upcoming: 'Upcoming Movies', trending: 'Trending', }); @@ -94,7 +94,7 @@ const Discover: React.FC = () => { /> ))} placeholder={} - emptyMessage={intl.formatMessage(messages.nopending)} + emptyMessage={intl.formatMessage(messages.noRequests)} /> = ({ open, setClosed }) => { const intl = useIntl(); const { hasPermission } = useUser(); useClickOutside(navRef, () => setClosed()); + return ( <>
@@ -172,7 +174,7 @@ const Sidebar: React.FC = ({ open, setClosed }) => {
@@ -181,7 +183,7 @@ const Sidebar: React.FC = ({ open, setClosed }) => {
-
@@ -273,6 +278,7 @@ const Sidebar: React.FC = ({ open, setClosed }) => { ); })} + {hasPermission(Permission.ADMIN) && }
diff --git a/src/components/Layout/VersionStatus/index.tsx b/src/components/Layout/VersionStatus/index.tsx new file mode 100644 index 00000000..e5e07869 --- /dev/null +++ b/src/components/Layout/VersionStatus/index.tsx @@ -0,0 +1,138 @@ +import Link from 'next/link'; +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import useSWR from 'swr'; +import { StatusResponse } from '../../../../server/interfaces/api/settingsInterfaces'; + +const messages = defineMessages({ + streamdevelop: 'Overseerr Develop', + streamstable: 'Overseerr Stable', + outofdate: 'Out of Date', + commitsbehind: + '{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind', +}); + +interface VersionStatusProps { + onClick?: () => void; +} + +const VersionStatus: React.FC = ({ onClick }) => { + const intl = useIntl(); + const { data } = useSWR('/api/v1/status', { + refreshInterval: 60 * 1000, + }); + + if (!data) { + return null; + } + + const versionStream = + data.commitTag === 'local' + ? 'Keep it up! 👍' + : data.version.startsWith('develop-') + ? intl.formatMessage(messages.streamdevelop) + : intl.formatMessage(messages.streamstable); + + return ( + + { + if (e.key === 'Enter' && onClick) { + onClick(); + } + }} + role="button" + tabIndex={0} + className={`flex items-center p-2 mx-2 text-xs transition duration-300 rounded-lg ring-1 ring-gray-700 ${ + data.updateAvailable + ? 'bg-yellow-500 text-white hover:bg-yellow-400' + : 'bg-gray-800 text-gray-300 hover:bg-gray-700' + }`} + > + {data.commitTag === 'local' ? ( + + + + ) : data.version.startsWith('develop-') ? ( + + + + ) : ( + + + + )} +
+ {versionStream} + + {data.commitTag === 'local' ? ( + '(⌐■_■)' + ) : data.commitsBehind > 0 ? ( + intl.formatMessage(messages.commitsbehind, { + commitsBehind: data.commitsBehind, + }) + ) : data.commitsBehind === -1 ? ( + intl.formatMessage(messages.outofdate) + ) : ( + + {data.version.replace('develop-', '')} + + )} + +
+ {data.updateAvailable && ( + + + + )} +
+ + ); +}; + +export default VersionStatus; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 330f7b3a..18519734 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -8,8 +8,8 @@ import Sidebar from './Sidebar'; import UserDropdown from './UserDropdown'; const messages = defineMessages({ - alphawarning: - 'This is ALPHA software. Features may be broken and/or unstable. Please report any issues on GitHub!', + betawarning: + 'This is BETA software. Features may be broken and/or unstable. Please report any issues on GitHub!', }); const Layout: React.FC = ({ children }) => { @@ -102,7 +102,7 @@ const Layout: React.FC = ({ children }) => { diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index a865f1ab..dadd9c1a 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -49,7 +49,7 @@ const messages = defineMessages({ overviewunavailable: 'Overview unavailable.', manageModalTitle: 'Manage Movie', manageModalRequests: 'Requests', - manageModalNoRequests: 'No Requests', + manageModalNoRequests: 'No requests.', manageModalClearMedia: 'Clear All Media Data', manageModalClearMediaWarning: '* This will irreversibly remove all data for this movie, including any requests. If this item exists in your Plex library, the media information will be recreated during the next scan.', diff --git a/src/components/NotificationTypeSelector/NotificationType/index.tsx b/src/components/NotificationTypeSelector/NotificationType/index.tsx index 85224717..4085b2a6 100644 --- a/src/components/NotificationTypeSelector/NotificationType/index.tsx +++ b/src/components/NotificationTypeSelector/NotificationType/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { NotificationItem, hasNotificationType } from '..'; +import { hasNotificationType, NotificationItem } from '..'; interface NotificationTypeProps { option: NotificationItem; @@ -46,7 +46,7 @@ const NotificationType: React.FC = ({ />
-
diff --git a/src/components/RequestList/RequestItem/index.tsx b/src/components/RequestList/RequestItem/index.tsx index 6e76f994..f9f512c9 100644 --- a/src/components/RequestList/RequestItem/index.tsx +++ b/src/components/RequestList/RequestItem/index.tsx @@ -28,12 +28,66 @@ const messages = defineMessages({ requested: 'Requested', modified: 'Modified', modifieduserdate: '{date} by {user}', + mediaerror: 'The associated title for this request is no longer available.', + deleterequest: 'Delete Request', + cancelRequest: 'Cancel Request', }); const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { return (movie as MovieDetails).title !== undefined; }; +interface RequestItemErroProps { + mediaId?: number; + revalidateList: () => void; +} + +const RequestItemError: React.FC = ({ + mediaId, + revalidateList, +}) => { + const intl = useIntl(); + const { hasPermission } = useUser(); + + const deleteRequest = async () => { + await axios.delete(`/api/v1/media/${mediaId}`); + revalidateList(); + }; + + return ( +
+ + {intl.formatMessage(messages.mediaerror)} + + {hasPermission(Permission.MANAGE_REQUESTS) && mediaId && ( +
+ +
+ )} +
+ ); +}; + interface RequestItemProps { request: MediaRequest; revalidateList: () => void; @@ -48,7 +102,7 @@ const RequestItem: React.FC = ({ }); const { addToast } = useToasts(); const intl = useIntl(); - const { hasPermission } = useUser(); + const { user, hasPermission } = useUser(); const [showEditModal, setShowEditModal] = useState(false); const { locale } = useContext(LanguageContext); const url = @@ -108,9 +162,9 @@ const RequestItem: React.FC = ({ if (!title || !requestData) { return ( -
); } @@ -315,6 +369,31 @@ const RequestItem: React.FC = ({
+ {requestData.status === MediaRequestStatus.PENDING && + !hasPermission(Permission.MANAGE_REQUESTS) && + requestData.requestedBy.id === user?.id && ( + deleteRequest()} + confirmText={intl.formatMessage(globalMessages.areyousure)} + className="w-full" + > + + + + + {intl.formatMessage(messages.cancelRequest)} + + + )} {requestData.media[requestData.is4k ? 'status4k' : 'status'] === MediaStatus.UNKNOWN && requestData.status !== MediaRequestStatus.DECLINED && diff --git a/src/components/RequestModal/AdvancedRequester/index.tsx b/src/components/RequestModal/AdvancedRequester/index.tsx index c9f54f7b..f0bee3a4 100644 --- a/src/components/RequestModal/AdvancedRequester/index.tsx +++ b/src/components/RequestModal/AdvancedRequester/index.tsx @@ -1,7 +1,10 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { Listbox, Transition } from '@headlessui/react'; +import { isEqual } from 'lodash'; +import dynamic from 'next/dynamic'; import React, { useEffect, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import type { OptionsType, OptionTypeBase } from 'react-select'; import useSWR from 'swr'; import type { ServiceCommonServer, @@ -13,6 +16,13 @@ import globalMessages from '../../../i18n/globalMessages'; import { formatBytes } from '../../../utils/numberHelpers'; import { SmallLoadingSpinner } from '../../Common/LoadingSpinner'; +type OptionType = { + value: string; + label: string; +}; + +const Select = dynamic(() => import('react-select'), { ssr: false }); + const messages = defineMessages({ advancedoptions: 'Advanced Options', destinationserver: 'Destination Server', @@ -23,12 +33,16 @@ const messages = defineMessages({ folder: '{path} ({space})', requestas: 'Request As', languageprofile: 'Language Profile', + tags: 'Tags', + selecttags: 'Select tags', + notagoptions: 'No tags.', }); export type RequestOverrides = { server?: number; profile?: number; folder?: string; + tags?: number[]; language?: number; user?: User; }; @@ -77,6 +91,10 @@ const AdvancedRequester: React.FC = ({ defaultOverrides?.language ?? -1 ); + const [selectedTags, setSelectedTags] = useState( + defaultOverrides?.tags ?? [] + ); + const { data: serverData, isValidating, @@ -150,6 +168,9 @@ const AdvancedRequester: React.FC = ({ ? serverData.server.activeAnimeLanguageProfileId : serverData.server.activeLanguageProfileId) ); + const defaultTags = isAnime + ? serverData.server.activeAnimeTags + : serverData.server.activeTags; if ( defaultProfile && @@ -174,46 +195,43 @@ const AdvancedRequester: React.FC = ({ ) { setSelectedLanguage(defaultLanguage.id); } + + if ( + defaultTags && + !isEqual(defaultTags, selectedTags) && + (!defaultOverrides || defaultOverrides.tags === null) + ) { + setSelectedTags(defaultTags); + } } }, [serverData]); useEffect(() => { - if ( - defaultOverrides && - defaultOverrides.server !== null && - defaultOverrides.server !== undefined - ) { + if (defaultOverrides && defaultOverrides.server != null) { setSelectedServer(defaultOverrides.server); } - if ( - defaultOverrides && - defaultOverrides.profile !== null && - defaultOverrides.profile !== undefined - ) { + if (defaultOverrides && defaultOverrides.profile != null) { setSelectedProfile(defaultOverrides.profile); } - if ( - defaultOverrides && - defaultOverrides.folder !== null && - defaultOverrides.folder !== undefined - ) { + if (defaultOverrides && defaultOverrides.folder != null) { setSelectedFolder(defaultOverrides.folder); } - if ( - defaultOverrides && - defaultOverrides.language !== null && - defaultOverrides.language !== undefined - ) { + if (defaultOverrides && defaultOverrides.language != null) { setSelectedLanguage(defaultOverrides.language); } + + if (defaultOverrides && defaultOverrides.tags != null) { + setSelectedTags(defaultOverrides.tags); + } }, [ defaultOverrides?.server, defaultOverrides?.folder, defaultOverrides?.profile, defaultOverrides?.language, + defaultOverrides?.tags, ]); useEffect(() => { @@ -224,6 +242,7 @@ const AdvancedRequester: React.FC = ({ server: selectedServer ?? undefined, user: selectedUser ?? undefined, language: selectedLanguage ?? undefined, + tags: selectedTags, }); } }, [ @@ -232,6 +251,7 @@ const AdvancedRequester: React.FC = ({ selectedProfile, selectedUser, selectedLanguage, + selectedTags, ]); if (!data && !error) { @@ -436,9 +456,48 @@ const AdvancedRequester: React.FC = ({
)} + {!!data && selectedServer !== null && ( +
+ + ({ + label: tag.label, + value: tag.id, + })) + : [] + } + isMulti + isDisabled={!isValidated || isTesting} + placeholder={ + !isValidated + ? intl.formatMessage(messages.testFirstTags) + : isTesting + ? intl.formatMessage(messages.loadingTags) + : intl.formatMessage(messages.selecttags) + } + className="react-select-container" + classNamePrefix="react-select" + value={values.tags.map((tagId) => { + const foundTag = testResponse.tags.find( + (tag) => tag.id === tagId + ); + return { + value: foundTag?.id, + label: foundTag?.label, + }; + })} + onChange={( + value: OptionTypeBase | OptionsType | null + ) => { + if (!Array.isArray(value)) { + return; + } + setFieldValue( + 'tags', + value?.map((option) => option.value) + ); + }} + noOptionsMessage={() => + intl.formatMessage(messages.notagoptions) + } + /> +
+
{currentVersion.startsWith('develop-') && ( - - {intl.formatMessage(messages.runningDevelopMessage, { + {msg}; }, @@ -177,7 +176,7 @@ const Releases: React.FC = ({ currentVersion }) => { ); }, })} - + /> )} {data?.map((release, index) => { return ( diff --git a/src/components/Settings/SettingsAbout/index.tsx b/src/components/Settings/SettingsAbout/index.tsx index 26e66a95..e29c177e 100644 --- a/src/components/Settings/SettingsAbout/index.tsx +++ b/src/components/Settings/SettingsAbout/index.tsx @@ -1,14 +1,17 @@ import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; import useSWR from 'swr'; +import { + SettingsAboutResponse, + StatusResponse, +} from '../../../../server/interfaces/api/settingsInterfaces'; +import globalMessages from '../../../i18n/globalMessages'; import Error from '../../../pages/_error'; +import Badge from '../../Common/Badge'; import List from '../../Common/List'; import LoadingSpinner from '../../Common/LoadingSpinner'; -import { SettingsAboutResponse } from '../../../../server/interfaces/api/settingsInterfaces'; -import { defineMessages, useIntl } from 'react-intl'; -import Releases from './Releases'; -import Badge from '../../Common/Badge'; import PageTitle from '../../Common/PageTitle'; -import globalMessages from '../../../i18n/globalMessages'; +import Releases from './Releases'; const messages = defineMessages({ about: 'About', @@ -23,6 +26,8 @@ const messages = defineMessages({ helppaycoffee: 'Help Pay for Coffee', documentation: 'Documentation', preferredmethod: 'Preferred', + outofdate: 'Out of Date', + uptodate: 'Up to Date', }); const SettingsAbout: React.FC = () => { @@ -31,6 +36,8 @@ const SettingsAbout: React.FC = () => { '/api/v1/settings/about' ); + const { data: status } = useSWR('/api/v1/status'); + if (!data && !error) { return ; } @@ -49,8 +56,22 @@ const SettingsAbout: React.FC = () => { />
- - {data.version} + + {data.version.replace('develop-', '')} + {status?.updateAvailable ? ( + + {intl.formatMessage(messages.outofdate)} + + ) : ( + status?.commitTag !== 'local' && ( + + {intl.formatMessage(messages.uptodate)} + + ) + )} {intl.formatNumber(data.totalMediaItems)} diff --git a/src/components/Settings/SettingsLayout.tsx b/src/components/Settings/SettingsLayout.tsx index dd13cfe4..65f4d548 100644 --- a/src/components/Settings/SettingsLayout.tsx +++ b/src/components/Settings/SettingsLayout.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; import { defineMessages, useIntl } from 'react-intl'; -import PageTitle from '../Common/PageTitle'; import globalMessages from '../../i18n/globalMessages'; +import PageTitle from '../Common/PageTitle'; +import SettingsTabs, { SettingsRoute } from '../Common/SettingsTabs'; const messages = defineMessages({ menuGeneralSettings: 'General', @@ -16,14 +15,7 @@ const messages = defineMessages({ menuAbout: 'About', }); -interface SettingsRoute { - text: string; - route: string; - regex: RegExp; -} - const SettingsLayout: React.FC = ({ children }) => { - const router = useRouter(); const intl = useIntl(); const settingsRoutes: SettingsRoute[] = [ @@ -69,78 +61,11 @@ const SettingsLayout: React.FC = ({ children }) => { }, ]; - const activeLinkColor = - 'border-indigo-600 text-indigo-500 focus:outline-none focus:text-indigo-500 focus:border-indigo-500'; - - const inactiveLinkColor = - 'border-transparent text-gray-500 hover:text-gray-400 hover:border-gray-300 focus:outline-none focus:text-gray-4700 focus:border-gray-300'; - - const SettingsLink: React.FC<{ - route: string; - regex: RegExp; - isMobile?: boolean; - }> = ({ children, route, regex, isMobile = false }) => { - if (isMobile) { - return ; - } - - return ( - - - {children} - - - ); - }; return ( <>
-
- -
-
- -
+
{children}
diff --git a/src/components/Settings/SettingsNotifications.tsx b/src/components/Settings/SettingsNotifications.tsx index a6893a38..e5a3bf9a 100644 --- a/src/components/Settings/SettingsNotifications.tsx +++ b/src/components/Settings/SettingsNotifications.tsx @@ -1,11 +1,5 @@ -import axios from 'axios'; -import { Field, Form, Formik } from 'formik'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useToasts } from 'react-toast-notifications'; -import useSWR from 'swr'; import Bolt from '../../assets/bolt.svg'; import DiscordLogo from '../../assets/extlogos/discord.svg'; import PushbulletLogo from '../../assets/extlogos/pushbullet.svg'; @@ -13,38 +7,20 @@ import PushoverLogo from '../../assets/extlogos/pushover.svg'; import SlackLogo from '../../assets/extlogos/slack.svg'; import TelegramLogo from '../../assets/extlogos/telegram.svg'; import globalMessages from '../../i18n/globalMessages'; -import Error from '../../pages/_error'; -import Button from '../Common/Button'; -import LoadingSpinner from '../Common/LoadingSpinner'; import PageTitle from '../Common/PageTitle'; +import SettingsTabs, { SettingsRoute } from '../Common/SettingsTabs'; const messages = defineMessages({ notifications: 'Notifications', notificationsettings: 'Notification Settings', - notificationsettingsDescription: - 'Configure global notification settings. The options below will apply to all notification agents.', - notificationAgentsSettings: 'Notification Agents', notificationAgentSettingsDescription: - 'Choose the types of notifications to send, and which notification agents to use.', - notificationsettingssaved: 'Notification settings saved successfully!', - notificationsettingsfailed: 'Notification settings failed to save.', - enablenotifications: 'Enable Notifications', + 'Configure and enable notification agents.', email: 'Email', webhook: 'Webhook', }); -interface SettingsRoute { - text: string; - content: React.ReactNode; - route: string; - regex: RegExp; -} - const SettingsNotifications: React.FC = ({ children }) => { - const router = useRouter(); const intl = useIntl(); - const { addToast } = useToasts(); - const { data, error, revalidate } = useSWR('/api/v1/settings/notifications'); const settingsRoutes: SettingsRoute[] = [ { @@ -139,40 +115,6 @@ const SettingsNotifications: React.FC = ({ children }) => { }, ]; - const activeLinkColor = 'bg-indigo-700'; - const inactiveLinkColor = 'bg-gray-800'; - - const SettingsLink: React.FC<{ - route: string; - regex: RegExp; - isMobile?: boolean; - }> = ({ children, route, regex, isMobile = false }) => { - if (isMobile) { - return ; - } - - return ( - - - {children} - - - ); - }; - - if (!data && !error) { - return ; - } - - if (!data) { - return ; - } - return ( <> {

{intl.formatMessage(messages.notificationsettings)}

-

- {intl.formatMessage(messages.notificationsettingsDescription)} -

-
-
- { - try { - await axios.post('/api/v1/settings/notifications', { - enabled: values.enabled, - }); - addToast(intl.formatMessage(messages.notificationsettingssaved), { - appearance: 'success', - autoDismiss: true, - }); - } catch (e) { - addToast( - intl.formatMessage(messages.notificationsettingsfailed), - { - appearance: 'error', - autoDismiss: true, - } - ); - } finally { - revalidate(); - } - }} - > - {({ isSubmitting, values, setFieldValue }) => { - return ( -
-
- -
- { - setFieldValue('enabled', !values.enabled); - }} - /> -
-
-
-
- - - -
-
-
- ); - }} -
-
-
-

- {intl.formatMessage(messages.notificationAgentsSettings)} -

{intl.formatMessage(messages.notificationAgentSettingsDescription)}

-
-
- - -
-
- -
-
+
{children}
); diff --git a/src/components/Settings/SettingsPlex.tsx b/src/components/Settings/SettingsPlex.tsx index b52c6af6..d410bb49 100644 --- a/src/components/Settings/SettingsPlex.tsx +++ b/src/components/Settings/SettingsPlex.tsx @@ -38,9 +38,8 @@ const messages = defineMessages({ toastPlexConnecting: 'Attempting to connect to Plex…', toastPlexConnectingSuccess: 'Plex connection established successfully!', toastPlexConnectingFailure: 'Failed to connect to Plex.', - settingUpPlex: 'Setting Up Plex', settingUpPlexDescription: - 'To set up Plex, you can either enter your details manually or select a server retrieved from plex.tv. Press the button to the right of the dropdown to check connectivity and retrieve available servers.', + 'To set up Plex, you can either enter your details manually or select a server retrieved from plex.tv. Press the button to the right of the dropdown to fetch the list of available servers.', hostname: 'Hostname or IP Address', port: 'Port', enablessl: 'Enable SSL', @@ -81,7 +80,6 @@ interface PresetServerDisplay { ssl: boolean; uri: string; address: string; - host?: string; port: number; local: boolean; status?: boolean; @@ -94,7 +92,6 @@ interface SettingsPlexProps { const SettingsPlex: React.FC = ({ onComplete }) => { const [isSyncing, setIsSyncing] = useState(false); const [isRefreshingPresets, setIsRefreshingPresets] = useState(false); - const [submitError, setSubmitError] = useState(null); const [availableServers, setAvailableServers] = useState( null ); @@ -115,7 +112,6 @@ const SettingsPlex: React.FC = ({ onComplete }) => { hostname: Yup.string() .required(intl.formatMessage(messages.validationHostnameRequired)) .matches( - // eslint-disable-next-line /^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i, intl.formatMessage(messages.validationHostnameRequired) ), @@ -135,13 +131,12 @@ const SettingsPlex: React.FC = ({ onComplete }) => { dev.connection.forEach((conn) => finalPresets.push({ name: dev.name, - ssl: conn.protocol === 'https' ? true : false, + ssl: !conn.local && conn.protocol === 'https', uri: conn.uri, address: conn.address, port: conn.port, local: conn.local, - host: conn.host, - status: conn.status === 200 ? true : false, + status: conn.status === 200, message: conn.message, }) ); @@ -270,13 +265,13 @@ const SettingsPlex: React.FC = ({ onComplete }) => { {intl.formatMessage(messages.plexsettingsDescription)}

- - {intl.formatMessage(messages.settingUpPlexDescription, { + @@ -285,7 +280,8 @@ const SettingsPlex: React.FC = ({ onComplete }) => { ); }, })} - + type="info" + />
= ({ onComplete }) => { } as PlexSettings); revalidate(); - setSubmitError(null); if (toastId) { removeToast(toastId); } @@ -335,7 +330,6 @@ const SettingsPlex: React.FC = ({ onComplete }) => { autoDismiss: true, appearance: 'error', }); - setSubmitError(e.response.data.message); } }} > @@ -394,7 +388,7 @@ const SettingsPlex: React.FC = ({ onComplete }) => { const targPreset = availablePresets[Number(e.target.value)]; if (targPreset) { - setFieldValue('hostname', targPreset.host); + setFieldValue('hostname', targPreset.address); setFieldValue('port', targPreset.port); setFieldValue('useSsl', targPreset.ssl); } @@ -515,18 +509,6 @@ const SettingsPlex: React.FC = ({ onComplete }) => { />
- {submitError && ( -
- - {submitError} - -
- )}
diff --git a/src/components/Settings/SettingsServices.tsx b/src/components/Settings/SettingsServices.tsx index 2eb978eb..c4801a03 100644 --- a/src/components/Settings/SettingsServices.tsx +++ b/src/components/Settings/SettingsServices.tsx @@ -20,11 +20,9 @@ import SonarrModal from './SonarrModal'; const messages = defineMessages({ services: 'Services', radarrsettings: 'Radarr Settings', - radarrSettingsDescription: - 'Configure your Radarr connection below. You can have multiple Radarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.', sonarrsettings: 'Sonarr Settings', - sonarrSettingsDescription: - 'Configure your Sonarr connection below. You can have multiple Sonarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.', + serviceSettingsDescription: + 'Configure your {serverType} server(s) below. You can connect multiple {serverType} servers, but only two of them can be marked as defaults (one non-4K and one 4K). Administrators are able to override the server used to process new requests prior to approval.', deleteserverconfirm: 'Are you sure you want to delete this server?', ssl: 'SSL', default: 'Default', @@ -33,9 +31,12 @@ const messages = defineMessages({ activeProfile: 'Active Profile', addradarr: 'Add Radarr Server', addsonarr: 'Add Sonarr Server', - nodefault: 'No Default Server', - nodefaultdescription: - 'At least one server must be marked as default before any requests will make it to your services.', + noDefaultServer: + 'At least one {serverType} server must be marked as default in order for {mediaType} requests to be processed.', + noDefaultNon4kServer: + 'If you only have a single {serverType} server for both non-4K and 4K content (or if you only download 4K content), your {serverType} server should NOT be designated as a 4K server.', + mediaTypeMovie: 'movie', + mediaTypeSeries: 'series', }); interface ServerInstanceProps { @@ -229,7 +230,9 @@ const SettingsServices: React.FC = () => { {intl.formatMessage(messages.radarrsettings)}

- {intl.formatMessage(messages.radarrSettingsDescription)} + {intl.formatMessage(messages.serviceSettingsDescription, { + serverType: 'Radarr', + })}

{editRadarrModal.open && ( @@ -284,13 +287,31 @@ const SettingsServices: React.FC = () => { {radarrData && !radarrError && ( <> {radarrData.length > 0 && - !radarrData.some( - (radarr) => radarr.isDefault && !radarr.is4k - ) && ( - -

{intl.formatMessage(messages.nodefaultdescription)}

-
- )} + (!radarrData.some((radarr) => radarr.isDefault) ? ( + + ) : ( + !radarrData.some( + (radarr) => radarr.isDefault && !radarr.is4k + ) && ( + + {msg} + + ); + }, + })} + /> + ) + ))}
    {radarrData.map((radarr) => ( { {intl.formatMessage(messages.sonarrsettings)}

    - {intl.formatMessage(messages.sonarrSettingsDescription)} + {intl.formatMessage(messages.serviceSettingsDescription, { + serverType: 'Sonarr', + })}

@@ -355,13 +378,31 @@ const SettingsServices: React.FC = () => { {sonarrData && !sonarrError && ( <> {sonarrData.length > 0 && - !sonarrData.some( - (sonarr) => sonarr.isDefault && !sonarr.is4k - ) && ( - -

{intl.formatMessage(messages.nodefaultdescription)}

-
- )} + (!sonarrData.some((sonarr) => sonarr.isDefault) ? ( + + ) : ( + !sonarrData.some( + (sonarr) => sonarr.isDefault && !sonarr.is4k + ) && ( + + {msg} + + ); + }, + })} + /> + ) + ))}
    {sonarrData.map((sonarr) => ( import('react-select'), { ssr: false }); + const messages = defineMessages({ createsonarr: 'Add New Sonarr Server', + create4ksonarr: 'Add New 4K Sonarr Server', editsonarr: 'Edit Sonarr Server', + edit4ksonarr: 'Edit 4K Sonarr Server', validationNameRequired: 'You must provide a server name', validationHostnameRequired: 'You must provide a hostname or IP address', validationPortRequired: 'You must provide a valid port number', @@ -23,6 +34,7 @@ const messages = defineMessages({ toastSonarrTestFailure: 'Failed to connect to Sonarr.', add: 'Add Server', defaultserver: 'Default Server', + default4kserver: 'Default 4K Server', servername: 'Server Name', servernamePlaceholder: 'A Sonarr Server', hostname: 'Hostname or IP Address', @@ -49,6 +61,8 @@ const messages = defineMessages({ testFirstRootFolders: 'Test connection to load root folders', loadinglanguageprofiles: 'Loading language profiles…', testFirstLanguageProfiles: 'Test connection to load language profiles', + loadingTags: 'Loading tags…', + testFirstTags: 'Test connection to load tags', syncEnabled: 'Enable Scan', externalUrl: 'External URL', externalUrlPlaceholder: 'External URL pointing to your Sonarr server', @@ -57,6 +71,10 @@ const messages = defineMessages({ validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash', validationBaseUrlLeadingSlash: 'Base URL must have a leading slash', validationBaseUrlTrailingSlash: 'Base URL must not end in a trailing slash', + tags: 'Tags', + animeTags: 'Anime Tags', + notagoptions: 'No tags.', + selecttags: 'Select tags', }); interface TestResponse { @@ -72,6 +90,10 @@ interface TestResponse { id: number; name: string; }[]; + tags: { + id: number; + label: string; + }[]; } interface SonarrModalProps { @@ -94,6 +116,7 @@ const SonarrModal: React.FC = ({ profiles: [], rootFolders: [], languageProfiles: [], + tags: [], }); const SonarrSettingsSchema = Yup.object().shape({ name: Yup.string().required( @@ -102,7 +125,6 @@ const SonarrModal: React.FC = ({ hostname: Yup.string() .required(intl.formatMessage(messages.validationHostnameRequired)) .matches( - // eslint-disable-next-line /^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i, intl.formatMessage(messages.validationHostnameRequired) ), @@ -204,7 +226,7 @@ const SonarrModal: React.FC = ({ initialLoad.current = true; } }, - [addToast] + [addToast, intl] ); useEffect(() => { @@ -244,6 +266,8 @@ const SonarrModal: React.FC = ({ activeAnimeProfileId: sonarr?.activeAnimeProfileId, activeAnimeLanguageProfileId: sonarr?.activeAnimeLanguageProfileId, activeAnimeRootFolder: sonarr?.activeAnimeDirectory, + tags: sonarr?.tags ?? [], + animeTags: sonarr?.animeTags ?? [], isDefault: sonarr?.isDefault ?? false, is4k: sonarr?.is4k ?? false, enableSeasonFolders: sonarr?.enableSeasonFolders ?? false, @@ -282,6 +306,8 @@ const SonarrModal: React.FC = ({ : undefined, activeAnimeProfileName: animeProfileName ?? undefined, activeAnimeDirectory: values.activeAnimeRootFolder, + tags: values.tags, + animeTags: values.animeTags, is4k: values.is4k, isDefault: values.isDefault, enableSeasonFolders: values.enableSeasonFolders, @@ -352,14 +378,24 @@ const SonarrModal: React.FC = ({ onOk={() => handleSubmit()} title={ !sonarr - ? intl.formatMessage(messages.createsonarr) - : intl.formatMessage(messages.editsonarr) + ? intl.formatMessage( + values.is4k + ? messages.create4ksonarr + : messages.createsonarr + ) + : intl.formatMessage( + values.is4k ? messages.edit4ksonarr : messages.editsonarr + ) } >
    @@ -634,6 +670,62 @@ const SonarrModal: React.FC = ({ )}
    +
    + +
    + ({ + label: tag.label, + value: tag.id, + })) + : [] + } + isMulti + isDisabled={!isValidated} + placeholder={ + !isValidated + ? intl.formatMessage(messages.testFirstTags) + : isTesting + ? intl.formatMessage(messages.loadingTags) + : intl.formatMessage(messages.selecttags) + } + isLoading={isTesting} + className="react-select-container" + classNamePrefix="react-select" + value={ + isTesting + ? [] + : values.animeTags.map((tagId) => { + const foundTag = testResponse.tags.find( + (tag) => tag.id === tagId + ); + return { + value: foundTag?.id, + label: foundTag?.label, + }; + }) + } + onChange={( + value: OptionTypeBase | OptionsType | null + ) => { + if (!Array.isArray(value)) { + return; + } + setFieldValue( + 'animeTags', + value?.map((option) => option.value) + ); + }} + noOptionsMessage={() => + intl.formatMessage(messages.notagoptions) + } + /> +
    +
    -
    +
    setFieldValue('password', '')} />
    -
    +
    @@ -383,8 +406,8 @@ const UserList: React.FC = () => { id="password" name="password" type="password" + autoComplete="new-password" disabled={values.genpassword} - placeholder={intl.formatMessage(messages.password)} />
    {errors.password && touched.password && ( diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord.tsx new file mode 100644 index 00000000..244e1d0d --- /dev/null +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord.tsx @@ -0,0 +1,178 @@ +import axios from 'axios'; +import { Field, Form, Formik } from 'formik'; +import { useRouter } from 'next/router'; +import React, { useEffect, useState } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import { useToasts } from 'react-toast-notifications'; +import useSWR from 'swr'; +import * as Yup from 'yup'; +import { UserSettingsNotificationsResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces'; +import { + hasNotificationAgentEnabled, + NotificationAgentType, +} from '../../../../../server/lib/notifications/agenttypes'; +import { useUser } from '../../../../hooks/useUser'; +import globalMessages from '../../../../i18n/globalMessages'; +import Button from '../../../Common/Button'; +import LoadingSpinner from '../../../Common/LoadingSpinner'; + +const messages = defineMessages({ + discordsettingssaved: 'Discord notification settings saved successfully!', + discordsettingsfailed: 'Discord notification settings failed to save.', + enableDiscord: 'Enable Mentions', + discordId: 'User ID', + discordIdTip: + 'The ID number for your user account', + validationDiscordId: 'You must provide a valid user ID', +}); + +const UserNotificationsDiscord: React.FC = () => { + const intl = useIntl(); + const { addToast } = useToasts(); + const router = useRouter(); + const [notificationAgents, setNotificationAgents] = useState(0); + const { user } = useUser({ id: Number(router.query.userId) }); + const { data, error, revalidate } = useSWR( + user ? `/api/v1/user/${user?.id}/settings/notifications` : null + ); + + useEffect(() => { + setNotificationAgents( + data?.notificationAgents ?? NotificationAgentType.EMAIL + ); + }, [data]); + + const UserNotificationsDiscordSchema = Yup.object().shape({ + discordId: Yup.string() + .when('enableDiscord', { + is: true, + then: Yup.string() + .nullable() + .required(intl.formatMessage(messages.validationDiscordId)), + otherwise: Yup.string().nullable(), + }) + .matches(/^\d{17,18}$/, intl.formatMessage(messages.validationDiscordId)), + }); + + if (!data && !error) { + return ; + } + + return ( + { + try { + await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, { + notificationAgents, + pgpKey: data?.pgpKey, + discordId: values.discordId, + telegramChatId: data?.telegramChatId, + telegramSendSilently: data?.telegramSendSilently, + }); + addToast(intl.formatMessage(messages.discordsettingssaved), { + appearance: 'success', + autoDismiss: true, + }); + } catch (e) { + addToast(intl.formatMessage(messages.discordsettingsfailed), { + appearance: 'error', + autoDismiss: true, + }); + } finally { + revalidate(); + } + }} + > + {({ errors, touched, isSubmitting, isValid, values, setFieldValue }) => { + return ( + + {data?.discordEnabled && ( +
    + +
    + { + setNotificationAgents( + hasNotificationAgentEnabled( + NotificationAgentType.DISCORD, + notificationAgents + ) + ? notificationAgents - NotificationAgentType.DISCORD + : notificationAgents + NotificationAgentType.DISCORD + ); + setFieldValue('enableDiscord', !values.enableDiscord); + }} + /> +
    +
    + )} +
    + +
    +
    + +
    + {errors.discordId && touched.discordId && ( +
    {errors.discordId}
    + )} +
    +
    +
    +
    + + + +
    +
    + + ); + }} +
    + ); +}; + +export default UserNotificationsDiscord; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx new file mode 100644 index 00000000..b949fb95 --- /dev/null +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx @@ -0,0 +1,175 @@ +import axios from 'axios'; +import { Field, Form, Formik } from 'formik'; +import { useRouter } from 'next/router'; +import React, { useEffect, useState } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import { useToasts } from 'react-toast-notifications'; +import useSWR from 'swr'; +import * as Yup from 'yup'; +import { UserSettingsNotificationsResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces'; +import { + hasNotificationAgentEnabled, + NotificationAgentType, +} from '../../../../../server/lib/notifications/agenttypes'; +import { useUser } from '../../../../hooks/useUser'; +import globalMessages from '../../../../i18n/globalMessages'; +import Badge from '../../../Common/Badge'; +import Button from '../../../Common/Button'; +import LoadingSpinner from '../../../Common/LoadingSpinner'; +import { OpenPgpLink } from '../../../Settings/Notifications/NotificationsEmail'; + +const messages = defineMessages({ + emailsettingssaved: 'Email notification settings saved successfully!', + emailsettingsfailed: 'Email notification settings failed to save.', + enableEmail: 'Enable Notifications', + pgpPublicKey: 'PGP Public Key', + pgpPublicKeyTip: + 'Encrypt email messages using OpenPGP', + validationPgpPublicKey: 'You must provide a valid PGP public key', +}); + +const UserEmailSettings: React.FC = () => { + const intl = useIntl(); + const { addToast } = useToasts(); + const router = useRouter(); + const [notificationAgents, setNotificationAgents] = useState(0); + const { user } = useUser({ id: Number(router.query.userId) }); + const { data, error, revalidate } = useSWR( + user ? `/api/v1/user/${user?.id}/settings/notifications` : null + ); + + useEffect(() => { + setNotificationAgents( + data?.notificationAgents ?? NotificationAgentType.EMAIL + ); + }, [data]); + + const UserNotificationsEmailSchema = Yup.object().shape({ + pgpKey: Yup.string() + .nullable() + .matches( + /^-----BEGIN PGP PUBLIC KEY BLOCK-----.+-----END PGP PUBLIC KEY BLOCK-----$/, + intl.formatMessage(messages.validationPgpPublicKey) + ), + }); + + if (!data && !error) { + return ; + } + + return ( + { + try { + await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, { + notificationAgents, + pgpKey: values.pgpKey, + discordId: data?.discordId, + telegramChatId: data?.telegramChatId, + telegramSendSilently: data?.telegramSendSilently, + }); + addToast(intl.formatMessage(messages.emailsettingssaved), { + appearance: 'success', + autoDismiss: true, + }); + } catch (e) { + addToast(intl.formatMessage(messages.emailsettingsfailed), { + appearance: 'error', + autoDismiss: true, + }); + } finally { + revalidate(); + } + }} + > + {({ errors, touched, isSubmitting, isValid, values, setFieldValue }) => { + return ( +
    +
    + +
    + { + setNotificationAgents( + hasNotificationAgentEnabled( + NotificationAgentType.EMAIL, + notificationAgents + ) + ? notificationAgents - NotificationAgentType.EMAIL + : notificationAgents + NotificationAgentType.EMAIL + ); + setFieldValue('enableEmail', !values.enableEmail); + }} + /> +
    +
    +
    + +
    +
    + +
    + {errors.pgpKey && touched.pgpKey && ( +
    {errors.pgpKey}
    + )} +
    +
    +
    +
    + + + +
    +
    +
    + ); + }} +
    + ); +}; + +export default UserEmailSettings; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram.tsx new file mode 100644 index 00000000..6193e127 --- /dev/null +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram.tsx @@ -0,0 +1,217 @@ +import axios from 'axios'; +import { Field, Form, Formik } from 'formik'; +import { useRouter } from 'next/router'; +import React, { useEffect, useState } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import { useToasts } from 'react-toast-notifications'; +import useSWR from 'swr'; +import * as Yup from 'yup'; +import { UserSettingsNotificationsResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces'; +import { + hasNotificationAgentEnabled, + NotificationAgentType, +} from '../../../../../server/lib/notifications/agenttypes'; +import { useUser } from '../../../../hooks/useUser'; +import globalMessages from '../../../../i18n/globalMessages'; +import Button from '../../../Common/Button'; +import LoadingSpinner from '../../../Common/LoadingSpinner'; + +const messages = defineMessages({ + telegramsettingssaved: 'Telegram notification settings saved successfully!', + telegramsettingsfailed: 'Telegram notification settings failed to save.', + enableTelegram: 'Enable Notifications', + telegramChatId: 'Chat ID', + telegramChatIdTipLong: + 'Start a chat, add @get_id_bot, and issue the /my_id command', + sendSilently: 'Send Silently', + sendSilentlyDescription: 'Send notifications with no sound', + validationTelegramChatId: 'You must provide a valid chat ID', +}); + +const UserTelegramSettings: React.FC = () => { + const intl = useIntl(); + const { addToast } = useToasts(); + const router = useRouter(); + const [notificationAgents, setNotificationAgents] = useState(0); + const { user } = useUser({ id: Number(router.query.userId) }); + const { data, error, revalidate } = useSWR( + user ? `/api/v1/user/${user?.id}/settings/notifications` : null + ); + + useEffect(() => { + setNotificationAgents( + data?.notificationAgents ?? NotificationAgentType.EMAIL + ); + }, [data]); + + const UserNotificationsTelegramSchema = Yup.object().shape({ + telegramChatId: Yup.string() + .when('enableTelegram', { + is: true, + then: Yup.string() + .nullable() + .required(intl.formatMessage(messages.validationTelegramChatId)), + otherwise: Yup.string().nullable(), + }) + .matches( + /^-?\d+$/, + intl.formatMessage(messages.validationTelegramChatId) + ), + }); + + if (!data && !error) { + return ; + } + + return ( + { + try { + await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, { + notificationAgents, + pgpKey: data?.pgpKey, + discordId: data?.discordId, + telegramChatId: values.telegramChatId, + telegramSendSilently: values.telegramSendSilently, + }); + addToast(intl.formatMessage(messages.telegramsettingssaved), { + appearance: 'success', + autoDismiss: true, + }); + } catch (e) { + addToast(intl.formatMessage(messages.telegramsettingsfailed), { + appearance: 'error', + autoDismiss: true, + }); + } finally { + revalidate(); + } + }} + > + {({ errors, touched, isSubmitting, isValid, values, setFieldValue }) => { + return ( +
    +
    + +
    + { + setNotificationAgents( + hasNotificationAgentEnabled( + NotificationAgentType.TELEGRAM, + notificationAgents + ) + ? notificationAgents - NotificationAgentType.TELEGRAM + : notificationAgents + NotificationAgentType.TELEGRAM + ); + setFieldValue('enableTelegram', !values.enableTelegram); + }} + /> +
    +
    +
    + +
    +
    + +
    + {errors.telegramChatId && touched.telegramChatId && ( +
    {errors.telegramChatId}
    + )} +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    + ); + }} +
    + ); +}; + +export default UserTelegramSettings; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/index.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/index.tsx index df828e5b..b52db481 100644 --- a/src/components/UserProfile/UserSettings/UserNotificationSettings/index.tsx +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/index.tsx @@ -1,61 +1,88 @@ -import axios from 'axios'; -import { Field, Form, Formik } from 'formik'; import { useRouter } from 'next/router'; import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useToasts } from 'react-toast-notifications'; import useSWR from 'swr'; -import * as Yup from 'yup'; import { UserSettingsNotificationsResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces'; +import DiscordLogo from '../../../../assets/extlogos/discord.svg'; +import TelegramLogo from '../../../../assets/extlogos/telegram.svg'; import { useUser } from '../../../../hooks/useUser'; import globalMessages from '../../../../i18n/globalMessages'; import Error from '../../../../pages/_error'; -import Badge from '../../../Common/Badge'; -import Button from '../../../Common/Button'; import LoadingSpinner from '../../../Common/LoadingSpinner'; import PageTitle from '../../../Common/PageTitle'; -import { PgpLink } from '../../../Settings/Notifications/NotificationsEmail'; +import SettingsTabs, { SettingsRoute } from '../../../Common/SettingsTabs'; const messages = defineMessages({ notifications: 'Notifications', notificationsettings: 'Notification Settings', - enableNotifications: 'Enable Notifications', - discordId: 'Discord ID', - discordIdTip: - 'The ID number for your Discord user account', - validationDiscordId: 'You must provide a valid Discord user ID', - telegramChatId: 'Telegram Chat ID', - telegramChatIdTip: 'Add @get_id_bot to the chat', - telegramChatIdTipLong: - 'Start a chat, add @get_id_bot, and issue the /my_id command', - sendSilently: 'Send Telegram Messages Silently', - sendSilentlyDescription: 'Send notifications with no sound', - validationTelegramChatId: 'You must provide a valid Telegram chat ID', + email: 'Email', toastSettingsSuccess: 'Notification settings saved successfully!', toastSettingsFailure: 'Something went wrong while saving settings.', - pgpKey: 'PGP Public Key', - pgpKeyTip: 'Encrypt email messages', }); -const UserNotificationSettings: React.FC = () => { +const UserNotificationSettings: React.FC = ({ children }) => { const intl = useIntl(); - const { addToast } = useToasts(); const router = useRouter(); - const { user, mutate } = useUser({ id: Number(router.query.userId) }); - const { data, error, revalidate } = useSWR( + const { user } = useUser({ id: Number(router.query.userId) }); + const { data, error } = useSWR( user ? `/api/v1/user/${user?.id}/settings/notifications` : null ); - const UserNotificationSettingsSchema = Yup.object().shape({ - discordId: Yup.string() - .nullable() - .matches(/^\d{17,18}$/, intl.formatMessage(messages.validationDiscordId)), - telegramChatId: Yup.string() - .nullable() - .matches( - /^[-]?\d+$/, - intl.formatMessage(messages.validationTelegramChatId) + const settingsRoutes: SettingsRoute[] = [ + { + text: intl.formatMessage(messages.email), + content: ( + + + + + {intl.formatMessage(messages.email)} + ), + route: '/settings/notifications/email', + regex: /\/settings\/notifications\/email/, + hidden: !data?.emailEnabled, + }, + { + text: 'Discord', + content: ( + + + Discord + + ), + route: '/settings/notifications/discord', + regex: /\/settings\/notifications\/discord/, + }, + { + text: 'Telegram', + content: ( + + + Telegram + + ), + route: '/settings/notifications/telegram', + regex: /\/settings\/notifications\/telegram/, + hidden: !data?.telegramEnabled || !data?.telegramBotUsername, + }, + ]; + + settingsRoutes.forEach((settingsRoute) => { + settingsRoute.route = router.asPath.includes('/profile') + ? `/profile${settingsRoute.route}` + : `/users/${user?.id}${settingsRoute.route}`; }); if (!data && !error) { @@ -80,215 +107,8 @@ const UserNotificationSettings: React.FC = () => { {intl.formatMessage(messages.notificationsettings)}
    - { - try { - await axios.post( - `/api/v1/user/${user?.id}/settings/notifications`, - { - enableNotifications: values.enableNotifications, - discordId: values.discordId, - telegramChatId: values.telegramChatId, - telegramSendSilently: values.telegramSendSilently, - pgpKey: values.pgpKey, - } - ); - - addToast(intl.formatMessage(messages.toastSettingsSuccess), { - autoDismiss: true, - appearance: 'success', - }); - } catch (e) { - addToast(intl.formatMessage(messages.toastSettingsFailure), { - autoDismiss: true, - appearance: 'error', - }); - } finally { - revalidate(); - mutate(); - } - }} - > - {({ errors, touched, isSubmitting }) => { - return ( -
    -
    - -
    - -
    -
    -
    - -
    -
    - -
    - {errors.pgpKey && touched.pgpKey && ( -
    {errors.pgpKey}
    - )} -
    -
    -
    - -
    -
    - -
    - {errors.discordId && touched.discordId && ( -
    {errors.discordId}
    - )} -
    -
    -
    - -
    -
    - -
    - {errors.telegramChatId && touched.telegramChatId && ( -
    {errors.telegramChatId}
    - )} -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    - ); - }} -
    + +
    {children}
    ); }; diff --git a/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx b/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx index e73550fd..52b32a0c 100644 --- a/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx +++ b/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx @@ -6,7 +6,6 @@ import { defineMessages, useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; import useSWR from 'swr'; import * as Yup from 'yup'; -import useSettings from '../../../../hooks/useSettings'; import { Permission, useUser } from '../../../../hooks/useUser'; import globalMessages from '../../../../i18n/globalMessages'; import Error from '../../../../pages/_error'; @@ -30,17 +29,15 @@ const messages = defineMessages({ 'Password is too short; should be a minimum of 8 characters', validationConfirmPassword: 'You must confirm the new password', validationConfirmPasswordSame: 'Passwords must match', - nopasswordset: 'No Password Set', - nopasswordsetDescription: - 'This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a "local user."', - nopasswordsetDescriptionOwnAccount: - 'Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a "local user" using your email address.', + noPasswordSet: + 'This user account currently does not have a password set. Configure a password below to enable this account to sign in as a "local user."', + noPasswordSetOwnAccount: + 'Your account currently does not have a password set. Configure a password below to enable sign-in as a "local user" using your email address.', nopermissionDescription: "You do not have permission to modify this user's password.", }); const UserPasswordChange: React.FC = () => { - const settings = useSettings(); const intl = useIntl(); const { addToast } = useToasts(); const router = useRouter(); @@ -88,11 +85,9 @@ const UserPasswordChange: React.FC = () => {

    {intl.formatMessage(messages.password)}

    - {intl.formatMessage(messages.nopermissionDescription)} - + /> ); } @@ -153,18 +148,12 @@ const UserPasswordChange: React.FC = () => { {!data.hasPassword && ( - {intl.formatMessage( + title={intl.formatMessage( user?.id === currentUser?.id - ? messages.nopasswordsetDescriptionOwnAccount - : messages.nopasswordsetDescription, - { - applicationTitle: - settings.currentSettings.applicationTitle, - } + ? messages.noPasswordSetOwnAccount + : messages.noPasswordSet )} - + /> )} {data.hasPassword && user?.id === currentUser?.id && (
    @@ -176,7 +165,8 @@ const UserPasswordChange: React.FC = () => {
    {errors.currentPassword && touched.currentPassword && ( @@ -191,7 +181,12 @@ const UserPasswordChange: React.FC = () => {
    - +
    {errors.newPassword && touched.newPassword && (
    {errors.newPassword}
    @@ -207,7 +202,8 @@ const UserPasswordChange: React.FC = () => {
    {errors.confirmPassword && touched.confirmPassword && ( diff --git a/src/components/UserProfile/UserSettings/UserPermissions/index.tsx b/src/components/UserProfile/UserSettings/UserPermissions/index.tsx index 057b9219..e89682d4 100644 --- a/src/components/UserProfile/UserSettings/UserPermissions/index.tsx +++ b/src/components/UserProfile/UserSettings/UserPermissions/index.tsx @@ -48,11 +48,9 @@ const UserPermissions: React.FC = () => {
    - {intl.formatMessage(messages.unauthorizedDescription)} - + /> ); } diff --git a/src/components/UserProfile/UserSettings/index.tsx b/src/components/UserProfile/UserSettings/index.tsx index d6babb63..74dffbd7 100644 --- a/src/components/UserProfile/UserSettings/index.tsx +++ b/src/components/UserProfile/UserSettings/index.tsx @@ -1,7 +1,8 @@ -import Link from 'next/link'; import { useRouter } from 'next/router'; import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import useSWR from 'swr'; +import { UserSettingsNotificationsResponse } from '../../../../server/interfaces/api/userSettingsInterfaces'; import { hasPermission, Permission } from '../../../../server/lib/permissions'; import useSettings from '../../../hooks/useSettings'; import { useUser } from '../../../hooks/useUser'; @@ -10,6 +11,7 @@ import Error from '../../../pages/_error'; import Alert from '../../Common/Alert'; import LoadingSpinner from '../../Common/LoadingSpinner'; import PageTitle from '../../Common/PageTitle'; +import SettingsTabs, { SettingsRoute } from '../../Common/SettingsTabs'; import ProfileHeader from '../ProfileHeader'; const messages = defineMessages({ @@ -21,21 +23,15 @@ const messages = defineMessages({ "You do not have permission to modify this user's settings.", }); -interface SettingsRoute { - text: string; - route: string; - regex: RegExp; - requiredPermission?: Permission | Permission[]; - permissionType?: { type: 'and' | 'or' }; - hidden?: boolean; -} - const UserSettings: React.FC = ({ children }) => { const router = useRouter(); const settings = useSettings(); const { user: currentUser } = useUser(); const { user, error } = useUser({ id: Number(router.query.userId) }); const intl = useIntl(); + const { data } = useSWR( + user ? `/api/v1/user/${user?.id}/settings/notifications` : null + ); if (!user && !error) { return ; @@ -67,7 +63,9 @@ const UserSettings: React.FC = ({ children }) => { }, { text: intl.formatMessage(messages.menuNotifications), - route: '/settings/notifications', + route: data?.emailEnabled + ? '/settings/notifications/email' + : '/settings/notifications/discord', regex: /\/settings\/notifications/, }, { @@ -79,38 +77,6 @@ const UserSettings: React.FC = ({ children }) => { }, ]; - const activeLinkColor = - 'border-indigo-600 text-indigo-500 focus:outline-none focus:text-indigo-500 focus:border-indigo-500'; - - const inactiveLinkColor = - 'border-transparent text-gray-500 hover:text-gray-400 hover:border-gray-300 focus:outline-none focus:text-gray-4700 focus:border-gray-300'; - - const SettingsLink: React.FC<{ - route: string; - regex: RegExp; - isMobile?: boolean; - }> = ({ children, route, regex, isMobile = false }) => { - const finalRoute = router.asPath.includes('/profile') - ? `/profile${route}` - : `/users/${user.id}${route}`; - if (isMobile) { - return ; - } - - return ( - - - {children} - - - ); - }; - if (currentUser?.id !== 1 && user.id === 1) { return ( <> @@ -123,23 +89,19 @@ const UserSettings: React.FC = ({ children }) => {
    - {intl.formatMessage(messages.unauthorizedDescription)} - + />
    ); } - const currentRoute = settingsRoutes.find( - (route) => !!router.pathname.match(route.regex) - )?.route; - - const finalRoute = router.asPath.includes('/profile') - ? `/profile${currentRoute}` - : `/users/${user.id}${currentRoute}`; + settingsRoutes.forEach((settingsRoute) => { + settingsRoute.route = router.asPath.includes('/profile') + ? `/profile${settingsRoute.route}` + : `/users/${user.id}${settingsRoute.route}`; + }); return ( <> @@ -151,68 +113,7 @@ const UserSettings: React.FC = ({ children }) => { />
    -
    - -
    -
    -
    - -
    -
    +
    {children}
    diff --git a/src/components/UserProfile/index.tsx b/src/components/UserProfile/index.tsx index 6966bd2f..f9a6d311 100644 --- a/src/components/UserProfile/index.tsx +++ b/src/components/UserProfile/index.tsx @@ -21,7 +21,7 @@ import ProfileHeader from './ProfileHeader'; const messages = defineMessages({ recentrequests: 'Recent Requests', - norequests: 'No Requests', + norequests: 'No requests.', limit: '{remaining} of {limit}', requestsperdays: '{limit} remaining', unlimited: 'Unlimited', diff --git a/src/context/SettingsContext.tsx b/src/context/SettingsContext.tsx index 8e83a4c9..8c9033f0 100644 --- a/src/context/SettingsContext.tsx +++ b/src/context/SettingsContext.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces'; import useSWR from 'swr'; +import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces'; export interface SettingsContextProps { currentSettings: PublicSettingsResponse; diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts index 2e737d55..867303f1 100644 --- a/src/hooks/useUser.ts +++ b/src/hooks/useUser.ts @@ -26,7 +26,6 @@ export interface User { } export interface UserSettings { - enableNotifications: boolean; discordId?: string; region?: string; originalLanguage?: string; diff --git a/src/i18n/globalMessages.ts b/src/i18n/globalMessages.ts index f40e80a5..884acc4a 100644 --- a/src/i18n/globalMessages.ts +++ b/src/i18n/globalMessages.ts @@ -43,7 +43,6 @@ const globalMessages = defineMessages({ loading: 'Loading…', settings: 'Settings', usersettings: 'User Settings', - unauthorized: 'Unauthorized', delimitedlist: '{a}, {b}', showingresults: 'Showing {from} to {to} of {total} results', diff --git a/src/i18n/locale/ca.json b/src/i18n/locale/ca.json index 8e13dbaf..443ae524 100644 --- a/src/i18n/locale/ca.json +++ b/src/i18n/locale/ca.json @@ -25,7 +25,6 @@ "components.RequestModal.autoapproval": "Aprovació automàtica", "components.RequestModal.alreadyrequested": "Ja s'ha sol·licitat", "components.RequestModal.SearchByNameModal.notvdbiddescription": "No s'ha pogut emparellat automàticament la vostra sol·licitud. Seleccioneu l'emparellament correcte de la llista següent.", - "components.RequestModal.SearchByNameModal.notvdbid": "Es requereix emparellament manual", "components.RequestModal.SearchByNameModal.nosummary": "No s'ha trobat cap sinopsi per a aquest títol.", "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {temporada} other {temporades}}", "components.RequestModal.QuotaDisplay.season": "temporada", @@ -78,7 +77,7 @@ "components.RequestBlock.rootfolder": "Carpeta arrel", "components.RequestBlock.requestoverrides": "Anul·lacions de sol·licituds", "components.RequestBlock.profilechanged": "Perfil de qualitat", - "components.RegionSelector.regionServerDefault": "({Region}) predeterminada", + "components.RegionSelector.regionServerDefault": "Predeterminada ({Region})", "components.PlexLoginButton.signinwithplex": "Inicieu la sessió", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} pel·lícula(es) per {quotaDays} dia(es)", "components.QuotaSelector.tvRequestLimit": "{quotaLimit} temporada(es) per {quotaDays} dia(es)", @@ -190,7 +189,6 @@ "components.Login.password": "Contrasenya", "components.Login.loginerror": "S'ha produït un error en intentar iniciar la sessió.", "components.Login.forgotpassword": "Has oblidat la contrasenya?", - "components.Layout.alphawarning": "Es tracta de programari en fase ALPHA. Moltes coses poden deixar de funcionar i/o ser inestables. Informeu de qualsevol problema a GitHub de Overseerr!", "components.Layout.UserDropdown.signout": "Tanqueu la sessió", "components.Layout.UserDropdown.settings": "Configuració", "components.Layout.UserDropdown.myprofile": "Perfil", @@ -205,10 +203,9 @@ "components.Discover.upcoming": "Pròximes pel·lícules", "components.Discover.trending": "Tendències", "components.Discover.recentrequests": "Sol·licituds recents", - "components.Discover.recentlyAdded": "Recentment afegit", + "components.Discover.recentlyAdded": "Afegit recentment", "components.Discover.populartv": "Sèries populars", "components.Discover.popularmovies": "Pel·lícules populars", - "components.Discover.nopending": "No hi ha sol·licituds pendents", "components.Discover.discovertv": "Sèries populars", "components.Discover.discovermovies": "Pel·lícules populars", "components.Discover.discover": "Descobriu", @@ -232,7 +229,6 @@ "components.CollectionDetails.overview": "Sinopsi", "components.CollectionDetails.numberofmovies": "{count} Pel·lícules", "components.AppDataWarning.dockerVolumeMissingDescription": "El muntatge de volum {appDataPath} no s'ha configurat correctament. Totes les dades s’esborraran quan el contenidor s’aturi o es reiniciï.", - "components.AppDataWarning.dockerVolumeMissing": "Falta el muntatge del volum de Docker", "components.RequestModal.requestfrom": "Hi ha una sol·licitud pendent de {username}.", "components.RequestModal.requesterror": "S'ha produït un error en enviar la sol·licitud.", "components.RequestModal.requestedited": "Sol·licitud per a {title} editada correctament!", @@ -247,27 +243,21 @@ "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "La configuració de notificacions Slack s'ha desat correctament!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "No s'ha pogut desar la configuració de notificacions Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Per configurar les notificacions Slack, haureu de crear una integració de WebhooK i introduir l'URL del webhook a continuació.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Configuració de notificacions Slack", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Tipus de notificacions", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Activa l'agent", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Heu de proporcionar una clau d'usuari vàlida", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Heu de proporcionar un testimoni d’aplicació vàlid", "components.Settings.Notifications.NotificationsPushover.userToken": "Clau d'usuari", "components.Settings.Notifications.NotificationsPushover.testsent": "S'ha enviat la notificació de prova!", "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Per configurar les notificacions Pushover, haureu de registrar una aplicació i introduir el testimoni API a continuació. (Podeu utilitzar una de les nostres icones oficials a GitHub.) També necessitareu la vostra clau d'usuari.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Configuració de notificacions Pushover", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "La configuració de notificacions Pushover s'ha desat correctament!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "No s'ha pogut desar la configuració de les notificacions de Pushover.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Tipus de notificacions", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Activa l'agent", "components.Settings.Notifications.NotificationsPushover.accessToken": "Testimoni d'aplicació / API", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Heu de proporcionar un testimoni d'accés", "components.Settings.Notifications.NotificationsPushbullet.testSent": "S'ha enviat la notificació de prova!", "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Per configurar les notificacions de Pushbullet, haureu de crear un testimoni d'accés i introduir-lo a continuació.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configuració de notificacions Pushbullet", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "La configuració de les notificacions de pushbullet s'ha desat correctament!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "No s'ha pogut desar la configuració de notificacions de Pushbullet.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Tipus de notificacions", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Activa l'agent", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Testimoni d'accés", "components.Search.searchresults": "Resultats de la cerca", @@ -309,11 +299,484 @@ "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Ajuda de la variable de plantilla", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "El Payload de JSON s'ha restablert correctament!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Restableix els valors per defecte", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Tipus de notificacions", "components.Settings.Notifications.NotificationsWebhook.customJson": "Payload de JSON", "components.Settings.Notifications.NotificationsWebhook.authheader": "Capçalera d'autorització", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Activa l'agent", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL del Webhook", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "Les notificacions per correu electrònic sobre mitjans sol·licitats, mitjans aprovats automàticament, mitjans fallits s'envien a tots els usuaris amb permís de Gestió de Sol·licituds.", - "components.Settings.Notifications.emailNotificationTypesAlert": "Destinataris de notificacions per correu electrònic" + "i18n.processing": "En procés", + "i18n.close": "Tanca", + "i18n.advanced": "Avançat", + "i18n.previous": "Endarrere", + "pages.somethingwentwrong": "Alguna cosa ha anat malament", + "pages.serviceunavailable": "Servei no disponible", + "pages.returnHome": "Torna a l'inici", + "pages.pagenotfound": "No s'ha trobat la pàgina", + "pages.oops": "Vaja", + "pages.internalservererror": "S'ha produït un error intern al servidor", + "pages.errormessagewithcode": "{statusCode} - {error}", + "i18n.view": "Mostra", + "i18n.usersettings": "Configuració de l'usuari", + "i18n.unavailable": "No disponible", + "i18n.tvshows": "Sèries", + "i18n.tvshow": "Sèries", + "i18n.testing": "S'està provant…", + "i18n.test": "Prova", + "i18n.status": "Estat", + "i18n.showingresults": "Mostrant {from} a {to} de {total} resultats", + "i18n.settings": "Configuració", + "i18n.saving": "S'està desant…", + "i18n.save": "Deseu els canvis", + "i18n.retry": "Torna-ho a provar", + "i18n.resultsperpage": "Mostra {pageSize} resultats per pàgina", + "i18n.requesting": "S'està sol·licitant …", + "i18n.requested": "Sol·licitat", + "i18n.request4k": "Sol·licita 4K", + "i18n.request": "Sol·licita", + "i18n.pending": "Pendent", + "i18n.partiallyavailable": "Parcialment disponible", + "i18n.notrequested": "No sol·licitat", + "i18n.noresults": "Sense resultats.", + "i18n.next": "Endavant", + "i18n.movies": "Pel·lícules", + "i18n.movie": "Pel·lícula", + "i18n.loading": "S'està carregant…", + "i18n.failed": "Fallit", + "i18n.experimental": "Experimental", + "i18n.edit": "Edita", + "i18n.delimitedlist": "{a}, {b}", + "i18n.delete": "Suprimeix", + "i18n.deleting": "S'està suprimint…", + "i18n.declined": "Rebutjat", + "i18n.decline": "Rebutja", + "i18n.canceling": "S'està cancel·lant …", + "i18n.cancel": "Canceŀla", + "i18n.back": "Torna", + "i18n.available": "Disponible", + "i18n.areyousure": "N'esteu segur?", + "i18n.approved": "Aprovat", + "i18n.approve": "Aprova", + "i18n.all": "Totes", + "components.UserProfile.unlimited": "Il·limitat", + "components.UserProfile.totalrequests": "Sol·licituds totals", + "components.UserProfile.seriesrequest": "Sol·licituds de sèries", + "components.UserProfile.requestsperdays": "{limit} restants", + "components.UserProfile.recentrequests": "Sol·licituds recents", + "components.UserProfile.pastdays": "{type} (últims {days} dies)", + "components.UserProfile.norequests": "Sense sol·licituds", + "components.UserProfile.movierequests": "Sol·licituds de pel·lícules", + "components.UserProfile.limit": "{remaining} de {limit}", + "components.UserProfile.UserSettings.unauthorizedDescription": "No teniu permís per modificar la configuració d'aquest usuari.", + "components.UserProfile.UserSettings.menuPermissions": "Permisos", + "components.UserProfile.UserSettings.menuNotifications": "Notificacions", + "components.UserProfile.UserSettings.menuGeneralSettings": "General", + "components.UserProfile.UserSettings.menuChangePass": "Contrasenya", + "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "No podeu modificar els vostres propis permisos.", + "components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Els permisos s'han desat correctament!", + "components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "S'ha produït un error en desar la configuració.", + "components.UserProfile.UserSettings.UserPermissions.permissions": "Permisos", + "components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "La contrasenya és massa curta; ha de tenir un mínim de 8 caràcters", + "components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "Heu de proporcionar una nova contrasenya", + "components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "Heu de proporcionar la vostra contrasenya actual", + "components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame": "Les contrasenyes han de coincidir", + "components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "Heu de confirmar la nova contrasenya", + "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "La contrasenya s'ha desat correctament!", + "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "S'ha produït un error en desar la contrasenya. La vostra contrasenya actual s'ha introduït correctament?", + "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "S'ha produït un error en desar la contrasenya.", + "components.UserProfile.UserSettings.UserPasswordChange.password": "Contrasenya", + "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "No teniu permís per modificar la contrasenya d'aquest usuari.", + "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nova contrasenya", + "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Contrasenya actual", + "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirmeu la contrasenya", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Heu de proporcionar un identificador de xat de Telegram vàlid", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Heu de proporcionar un identificador d'usuari Discord vàlid", + "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "La configuració de les notificacions s'ha desat correctament!", + "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "S'ha produït un error en desar la configuració.", + "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "La configuració s'ha desat correctament!", + "components.UserProfile.UserSettings.UserGeneralSettings.role": "Rol", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Inicieu un xat, afegiu @get_id_bot i executeu l'ordre / my_id", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Identificador de xat de Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Envia notificacions sense so", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Envia missatges de Telegram silenciosament", + "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Configuració de les notificacions", + "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notificacions", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "El número d'identificació del vostre compte d'usuari Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID de Discord", + "components.UserProfile.UserSettings.UserGeneralSettings.user": "Usuari", + "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "S'ha produït un error en desar la configuració.", + "components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit": "Límit de sol·licituds de sèries", + "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filtra el contingut per disponibilitat regional", + "components.UserProfile.UserSettings.UserGeneralSettings.region": "Regió per a la secció \"Descobriu\"", + "components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Usuari de Plex", + "components.UserProfile.UserSettings.UserGeneralSettings.owner": "Propietari", + "components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filtra el contingut per l'idioma original", + "components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Idioma per a la secció \"Descobriu\"", + "components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit": "Límit de sol·licituds de pel·lícules", + "components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Usuari local", + "components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "Configuració general", + "components.UserProfile.UserSettings.UserGeneralSettings.general": "General", + "components.UserProfile.UserSettings.UserGeneralSettings.enableOverride": "Activa la sobreescriptura", + "components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Nom de visualització", + "components.UserProfile.UserSettings.UserGeneralSettings.admin": "Administrador", + "components.UserProfile.UserSettings.UserGeneralSettings.accounttype": "Tipus de compte", + "components.UserProfile.ProfileHeader.userid": "ID d'usuari: {userid}", + "components.UserProfile.ProfileHeader.settings": "Edita la configuració", + "components.UserProfile.ProfileHeader.profile": "Mostra el perfil", + "components.UserProfile.ProfileHeader.joindate": "Unit el {joindate}", + "components.UserList.validationpasswordminchars": "La contrasenya és massa curta; ha de tenir un mínim de 8 caràcters", + "components.UserList.validationEmail": "Heu de proporcionar una adreça de correu electrònic vàlida", + "components.UserList.userssaved": "Els permisos d'usuari s'han desat correctament!", + "components.UserList.users": "Usuaris", + "components.UserList.userlist": "Llista d'usuaris", + "components.UserList.userfail": "S'ha produït un error en desar els permisos de l'usuari.", + "components.UserList.userdeleteerror": "S'ha produït un error en suprimir l'usuari.", + "components.TvDetails.overviewunavailable": "Sinopsi no disponible.", + "components.TvDetails.overview": "Sinopsi", + "components.TvDetails.originaltitle": "Títol original", + "components.TvDetails.originallanguage": "Idioma original", + "components.TvDetails.opensonarr4k": "Obre la sèrie 4K a Sonarr", + "components.TvDetails.opensonarr": "Obre la sèrie a Sonarr", + "components.TvDetails.nextAirDate": "Pròxima data d'emissió", + "components.TvDetails.network": "{networkCount, plural, one {Plataforma} other {Plataformes}}", + "components.StatusChacker.reloadOverseerr": "Torna a Carregar", + "components.TvDetails.markavailable": "Marca com a disponible", + "components.TvDetails.mark4kavailable": "Marca 4K com a disponible", + "components.TvDetails.manageModalTitle": "Gestiona les sèries", + "components.TvDetails.manageModalRequests": "Sol·licituds", + "components.TvDetails.manageModalNoRequests": "Sense sol·licituds", + "components.TvDetails.manageModalClearMediaWarning": "* Això eliminarà irreversiblement totes les dades d'aquesta sèrie de televisió, incloses les sol·licituds. Si aquest ítem existeix a la vostra biblioteca Plex, la informació multimèdia es recrearà durant la propera exploració.", + "components.TvDetails.manageModalClearMedia": "Esborra totes les dades de mitjans", + "components.TvDetails.firstAirDate": "Primera data d'emissió", + "components.TvDetails.episodeRuntimeMinutes": "{runtime} minuts", + "components.TvDetails.episodeRuntime": "Duració de l'episodi", + "components.TvDetails.downloadstatus": "Estat de la baixada", + "components.TvDetails.cast": "Repartiment", + "components.TvDetails.anime": "Anime", + "components.TvDetails.allseasonsmarkedavailable": "* Totes les temporades estaran marcades com a disponibles.", + "components.TvDetails.TvCrew.fullseriescrew": "Equip complet de la sèrie", + "components.TvDetails.TvCast.fullseriescast": "Repartiment complet de la sèrie", + "components.StatusChacker.newversionavailable": "Actualització de l'aplicació", + "components.StatusChacker.newversionDescription": "Overseerr s'ha actualitzat! Feu clic al botó següent per tornar a carregar la pàgina.", + "components.StatusBadge.status4k": "4K {status}", + "components.Setup.welcome": "Benvingut a Overseerr", + "components.Setup.tip": "Consell", + "components.Setup.signinMessage": "Comenceu iniciant sessió amb el vostre compte de Plex", + "components.Setup.setup": "Configuració", + "components.Setup.scanbackground": "L’exploració s’executarà en segon pla. Mentrestant, podeu continuar el procés de configuració.", + "components.Setup.loginwithplex": "Inicieu sessió amb Plex", + "components.Setup.finishing": "S'està acabant…", + "components.Setup.finish": "Finalitza la configuració", + "components.Setup.continue": "Continua", + "components.Setup.configureservices": "Configureu els serveis", + "components.Settings.trustProxy": "Activeu l'assistència de servidor intermediari", + "components.Settings.toastPlexRefresh": "S'està recuperant la llista de servidors de Plex…", + "components.Setup.configureplex": "Configureu Plex", + "components.Settings.webhook": "Webhook", + "components.Settings.validationPortRequired": "Heu de proporcionar un número de port vàlid", + "components.Settings.validationHostnameRequired": "Heu de proporcionar un nom d’amfitrió o una adreça IP", + "components.Settings.validationApplicationUrlTrailingSlash": "L'URL no pot acabar amb una barra inclinada final", + "components.Settings.validationApplicationUrl": "Heu de proporcionar un URL vàlid", + "components.Settings.validationApplicationTitle": "Heu de proporcionar un títol d'aplicació", + "components.Settings.trustProxyTip": "Permet a Overseerr registrar correctament les adreces IP del client darrere d’un servidor intermediari (s’ha de tornar a carregar Overseerr perquè els canvis tinguin efecte)", + "components.Settings.toastSettingsSuccess": "La configuració s'ha desat correctament!", + "components.Settings.toastSettingsFailure": "S'ha produït un error en desar la configuració.", + "components.Settings.toastPlexRefreshSuccess": "La llista de servidors Plex s'ha recuperat correctament!", + "components.Settings.toastPlexRefreshFailure": "No s'ha pogut recuperar la llista de servidors Plex.", + "components.Settings.toastPlexConnectingSuccess": "La connexió amb Plex s'ha establert correctament!", + "components.Settings.toastPlexConnectingFailure": "No s'ha pogut connectar amb Plex.", + "components.Settings.toastPlexConnecting": "S'està intentant connectar amb Plex…", + "components.Settings.toastApiKeySuccess": "Nova clau d'API generada correctament!", + "components.Settings.toastApiKeyFailure": "S'ha produït un error en generar una nova clau API.", + "components.Settings.timeout": "Temps d'espera", + "components.Settings.startscan": "Inicia l'exploració", + "components.Settings.ssl": "SSL", + "components.Settings.sonarrsettings": "Configuració de Sonarr", + "components.Settings.settingUpPlexDescription": "Per configurar Plex, podeu introduir les vostres dades manualment o seleccionar un servidor recuperat de plex.tv. Premeu el botó situat a la dreta del menú desplegable per comprovar la connectivitat i recuperar els servidors disponibles.", + "components.Settings.services": "Serveis", + "components.Settings.serverpresetRefreshing": "S'estan recuperant els servidors…", + "components.Settings.serverpresetPlaceholder": "Servidor Plex", + "components.Settings.serverpresetManualMessage": "Configuració manual", + "components.Settings.serverpresetLoad": "Premeu el botó per carregar els servidors disponibles", + "components.Settings.serverpreset": "Servidor", + "components.Settings.servernameTip": "Recuperat automàticament de Plex després de desar-lo", + "components.Settings.servernamePlaceholder": "Nom del Servidor Plex", + "components.Settings.servername": "Nom del Servidor", + "components.Settings.serverRemote": "remot", + "components.Settings.serverLocal": "local", + "components.Settings.serverConnected": "connectat", + "components.Settings.scanning": "S'està sincronitzant …", + "components.Settings.scan": "Sincronitza les biblioteques", + "components.Settings.regionTip": "Filtra el contingut per disponibilitat regional", + "components.Settings.region": "Regió per a la secció \"Descobriu\"", + "components.Settings.radarrsettings": "Configuració de Radarr", + "components.Settings.port": "Port", + "components.Settings.plexsettingsDescription": "Configureu la paràmetres del servidor Plex. Overseerr explora les vostres biblioteques Plex per veure quin contingut està disponible.", + "components.Settings.plexsettings": "Configuració de Plex", + "components.Settings.plexlibrariesDescription": "Les biblioteques en les que Overseerr explora títols. Configureu i deseu la configuració de la connexió Plex i feu clic al botó següent si no apareix cap.", + "components.Settings.plexlibraries": "Biblioteques Plex", + "components.Settings.plex": "Plex", + "components.Settings.partialRequestsEnabled": "Permet sol·licituds parcials de Sèries", + "components.Settings.originallanguageTip": "Filtra el contingut per l'idioma original", + "components.Settings.originallanguage": "Idioma per a la secció \"Descobriu\"", + "components.Settings.manualscanDescription": "Normalment, només s’executarà una vegada cada 24 hores. Overseerr comprovarà de forma més agressiva el contingut afegit recentment del seu servidor Plex. Si és la primera vegada que configureu Plex, es recomana fer una exploració manual completa de la biblioteca!", + "components.Settings.SettingsJobsCache.plex-recently-added-scan": "Exploració d'elements de Plex afegits recentment", + "components.Settings.notrunning": "No s'està executant", + "components.Settings.notificationsettings": "Configuració de les notificacions", + "components.Settings.notifications": "Notificacions", + "components.Settings.notificationAgentSettingsDescription": "Trieu el tipus de notificacions que voleu enviar i els agents de notificació que voleu utilitzar.", + "components.Settings.menuUsers": "Usuaris", + "components.Settings.menuServices": "Serveis", + "components.Settings.menuPlexSettings": "Plex", + "components.Settings.menuNotifications": "Notificacions", + "components.Settings.menuLogs": "Registres", + "components.Settings.menuJobs": "Tasques programades i memòria cau", + "components.Settings.hideAvailable": "Amaga els suports disponibles", + "components.Settings.generalsettingsDescription": "Configureu els paràmetres globals i predeterminats per a Overseerr.", + "components.Settings.menuGeneralSettings": "General", + "components.Settings.menuAbout": "Quant a", + "components.Settings.manualscan": "Exploració manual de la biblioteca", + "components.Settings.librariesRemaining": "Biblioteques restants: {count}", + "components.Settings.hostname": "Nom de l’amfitrió o adreça IP", + "components.Settings.generalsettings": "Configuració general", + "components.Settings.general": "General", + "components.Settings.deleteserverconfirm": "Esteu segur que voleu suprimir aquest servidor?", + "components.Settings.currentlibrary": "Biblioteca actual: {name}", + "components.Settings.cancelscan": "Cancel·la l'exploració", + "components.Settings.cacheImagesTip": "Optimitzeu i emmagatzemeu totes les imatges de forma local (consumeix una quantitat important d'espai en disc)", + "components.Settings.applicationTitle": "Títol de l'aplicació", + "components.Settings.addsonarr": "Afegeix un servidor Sonarr", + "components.Settings.activeProfile": "Perfil actiu", + "components.Settings.enablessl": "Activa SSL", + "components.Settings.email": "Adreça electrònica", + "components.Settings.default4k": "4K predeterminat", + "components.Settings.default": "Predeterminat", + "components.Settings.csrfProtectionTip": "Estableix l'accés a l'API externa de només lectura (requereix HTTPS i s'ha de tornar a carregar Overseerr perquè els canvis tinguin efecte)", + "components.Settings.csrfProtectionHoverTip": "NO activeu aquesta configuració tret que entengueu el que esteu fent!", + "components.Settings.csrfProtection": "Activeu la protecció CSRF", + "components.Settings.copied": "S'ha copiat la clau API al porta-retalls.", + "components.Settings.cacheImages": "Activa la memòria cau d'imatges", + "components.Settings.applicationurl": "URL de l'aplicació", + "components.Settings.apikey": "Clau API", + "components.Settings.address": "Adreça", + "components.Settings.addradarr": "Afegeix un servidor Radarr", + "components.Settings.SonarrModal.validationRootFolderRequired": "Heu de seleccionar una carpeta arrel", + "components.Settings.SonarrModal.validationProfileRequired": "Heu de seleccionar un perfil de qualitat", + "components.Settings.SonarrModal.validationPortRequired": "Heu de proporcionar un número de port vàlid", + "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", + "components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "L'URL base no pot 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", + "components.Settings.SonarrModal.validationApiKeyRequired": "Heu de proporcionar una clau API", + "components.Settings.SonarrModal.toastSonarrTestSuccess": "La connexió amb Sonarr s'ha establert correctament!", + "components.Settings.SonarrModal.toastSonarrTestFailure": "No s'ha pogut connectar amb Sonarr.", + "components.Settings.SonarrModal.testFirstRootFolders": "Proveu la connexió per carregar les carpetes arrel", + "components.Settings.SonarrModal.testFirstQualityProfiles": "Prova la connexió per carregar perfils de qualitat", + "components.Settings.SonarrModal.testFirstLanguageProfiles": "Prova la connexió per carregar els perfils d'idioma", + "components.Settings.SonarrModal.syncEnabled": "Activa l’escaneig", + "components.Settings.SonarrModal.ssl": "Activa SSL", + "components.Settings.SonarrModal.servernamePlaceholder": "Un servidor Sonarr", + "components.Settings.SonarrModal.servername": "Nom del Servidor", + "components.Settings.SonarrModal.server4k": "Servidor 4K", + "components.Settings.RadarrModal.selectRootFolder": "Seleccioneu la carpeta arrel", + "components.Settings.SonarrModal.selectRootFolder": "Seleccioneu la carpeta arrel", + "components.Settings.SonarrModal.selectQualityProfile": "Seleccioneu un perfil de qualitat", + "components.Settings.SonarrModal.selectLanguageProfile": "Seleccioneu el perfil d'idioma", + "components.Settings.SonarrModal.seasonfolders": "Carpeta per temporada", + "components.Settings.SonarrModal.rootfolder": "Carpeta arrel", + "components.Settings.SonarrModal.qualityprofile": "Perfil de qualitat", + "components.Settings.SonarrModal.preventSearch": "Desactiveu la cerca automàtica", + "components.Settings.SonarrModal.port": "Port", + "components.Settings.SonarrModal.loadingrootfolders": "S'estan carregant les carpetes arrel…", + "components.Settings.SonarrModal.loadingprofiles": "S'estan carregant els perfils de qualitat…", + "components.Settings.SonarrModal.loadinglanguageprofiles": "S'estan carregant els perfils d'idioma…", + "components.Settings.SonarrModal.languageprofile": "Perfil d'idioma", + "components.Settings.SonarrModal.hostname": "Nom de l’amfitrió o adreça IP", + "components.Settings.SonarrModal.externalUrlPlaceholder": "URL extern que apunta al servidor Sonarr", + "components.Settings.SonarrModal.externalUrl": "URL extern", + "components.Settings.SonarrModal.editsonarr": "Editeu el servidor Sonarr", + "components.Settings.SonarrModal.defaultserver": "Servidor predeterminat", + "components.Settings.SonarrModal.createsonarr": "Afegeix un nou servidor Sonarr", + "components.Settings.SonarrModal.baseUrlPlaceholder": "Exemple: /sonarr", + "components.Settings.SonarrModal.animequalityprofile": "Perfil de qualitat de l'anime", + "components.Settings.SettingsUsers.userSettingsDescription": "Configureu la configuració global i predeterminada de l'usuari.", + "components.Settings.SettingsUsers.toastSettingsFailure": "S'ha produït un error en desar la configuració.", + "components.Settings.RadarrModal.baseUrl": "URL base", + "components.Settings.SonarrModal.baseUrl": "URL base", + "components.Settings.SonarrModal.apiKeyPlaceholder": "La vostra clau API Sonarr", + "components.Settings.SonarrModal.apiKey": "Clau API", + "components.Settings.SonarrModal.animerootfolder": "Carpeta arrel de l'anime", + "components.Settings.SonarrModal.animelanguageprofile": "Perfil d'idioma per a Anime", + "components.Settings.SonarrModal.add": "Afegeix un servidor", + "components.Settings.SettingsUsers.users": "Usuaris", + "components.Settings.SettingsUsers.userSettings": "Configuració de l'usuari", + "components.Settings.SettingsUsers.tvRequestLimitLabel": "Límit global de sol·licituds de Sèries", + "components.Settings.SettingsUsers.toastSettingsSuccess": "La configuració de l'usuari s'ha desat correctament!", + "components.Settings.SettingsAbout.gettingsupport": "Obteniu d’ajuda", + "components.Settings.SettingsUsers.localLogin": "Activa l'inici de sessió local", + "components.Settings.SettingsLogs.time": "Marca de temps", + "components.Settings.SettingsLogs.resumeLogs": "Reprèn", + "components.Settings.SettingsLogs.pauseLogs": "Pausa", + "components.Settings.SettingsLogs.filterInfo": "Info", + "components.Settings.SettingsLogs.filterDebug": "Depuració", + "components.Settings.SettingsLogs.extraData": "Dades addicionals", + "components.Settings.SettingsLogs.copyToClipboard": "Copia al porta-retalls", + "components.Settings.SettingsLogs.copiedLogMessage": "S'ha copiat el missatge de registre al porta-retalls.", + "components.Settings.SettingsJobsCache.runnow": "Executa-ho ara", + "components.Settings.SettingsJobsCache.plex-full-scan": "Exploració completa de la biblioteca plex", + "components.Settings.SettingsJobsCache.nextexecution": "Pròxima execució", + "components.Settings.SettingsJobsCache.jobstarted": "S'ha iniciat {jobname}.", + "components.Settings.SettingsJobsCache.jobcancelled": "{jobname} s'ha cancel·lat.", + "components.Settings.SettingsJobsCache.flushcache": "Buida la memòria cau", + "components.Settings.SettingsJobsCache.command": "Ordre", + "components.Settings.SettingsJobsCache.cachevsize": "Mida del valor", + "components.Settings.SettingsJobsCache.cachename": "Nom de la memòria cau", + "components.Settings.SettingsJobsCache.cacheksize": "Mida de la clau", + "components.Settings.SettingsJobsCache.cachekeys": "Claus totals", + "components.Settings.SettingsJobsCache.cacheflushed": "La memòria cau de {cachename} s'ha buidat.", + "components.Settings.SettingsAbout.totalrequests": "Sol·licituds totals", + "components.Settings.SettingsAbout.totalmedia": "Total de suports multimèdia", + "components.Settings.SettingsAbout.preferredmethod": "Preferit", + "components.Settings.SettingsAbout.githubdiscussions": "Debats de GitHub", + "components.Settings.SettingsAbout.Releases.viewongithub": "Visualitza a GitHub", + "components.Settings.SettingsAbout.Releases.viewchangelog": "Visualitza el registre de canvis", + "components.Settings.SettingsAbout.Releases.versionChangelog": "Registre de canvis de versions", + "components.Settings.SettingsUsers.movieRequestLimitLabel": "Límit global de sol·licituds de pel·lícules", + "components.Settings.SettingsUsers.defaultPermissions": "Permisos per defecte", + "components.Settings.SettingsLogs.showall": "Mostra tots els registres", + "components.Settings.SettingsLogs.message": "Missatge", + "components.Settings.SettingsLogs.logsDescription": "També podeu veure aquests registres directament mitjançant stdout o a {configDir}/logs/overseerr.log.", + "components.Settings.SettingsLogs.logs": "Registres", + "components.Settings.SettingsLogs.logDetails": "Detalls del registre", + "components.Settings.SettingsLogs.level": "Gravetat", + "components.Settings.SettingsLogs.label": "Etiqueta", + "components.Settings.SettingsLogs.filterWarn": "Avís", + "components.Settings.SettingsLogs.filterError": "Error", + "components.Settings.SettingsJobsCache.unknownJob": "Tasca programada desconeguda", + "components.Settings.SettingsJobsCache.sonarr-scan": "Escaneig de Sonarr", + "components.Settings.SettingsJobsCache.radarr-scan": "Escaneig de Radarr", + "components.Settings.SettingsJobsCache.process": "Procés", + "components.Settings.SettingsJobsCache.jobtype": "Tipus", + "components.Settings.SettingsJobsCache.jobsandcache": "Tasques programades i memòria cau", + "components.Settings.SettingsJobsCache.jobsDescription": "Overseerr realitza certes tasques de manteniment com a feines programades regularment, però també es poden activar manualment a continuació. L’execució manual d’un treball no alterarà la seva programació.", + "components.Settings.SettingsJobsCache.jobs": "Tasques programades", + "components.Settings.SettingsJobsCache.jobname": "Nom de la tasca programada", + "components.Settings.SettingsJobsCache.download-sync-reset": "Restableix la sincronització de descàrregues", + "components.Settings.SettingsJobsCache.download-sync": "Sincronitza les baixades", + "components.Settings.SettingsJobsCache.canceljob": "Cancel·la la tasca programada", + "components.Settings.SettingsJobsCache.cachemisses": "Errades", + "components.Settings.SettingsJobsCache.cachehits": "Consultes", + "components.Settings.SettingsJobsCache.cacheDescription": "Overseerr emmagatzema a la memòria cau les sol·licituds als punts finals de l'API externa per optimitzar el rendiment i evitar fer peticions d'API innecessàries.", + "components.Settings.SettingsJobsCache.cache": "Memòria cau", + "components.Settings.SettingsAbout.version": "Versió", + "components.Settings.SettingsAbout.timezone": "Zona horària", + "components.Settings.SettingsAbout.supportoverseerr": "Dóna suport a Overseerr", + "components.Settings.SettingsAbout.overseerrinformation": "Informació d'Overseerr", + "components.Settings.SettingsAbout.helppaycoffee": "Ajudeu-me convidant-me a un cafè", + "components.Settings.SettingsAbout.documentation": "Documentació", + "components.Settings.SettingsAbout.about": "Quant a", + "components.Settings.SettingsAbout.Releases.currentversion": "Versió actual", + "components.Settings.RadarrModal.selectQualityProfile": "Seleccioneu un perfil de qualitat", + "components.Settings.RadarrModal.selectMinimumAvailability": "Seleccioneu la disponibilitat mínima", + "components.Settings.RadarrModal.minimumAvailability": "Disponibilitat mínima", + "components.Settings.RadarrModal.loadingrootfolders": "S'estan carregant les carpetes arrel…", + "components.Settings.RadarrModal.loadingprofiles": "S'estan carregant els perfils de qualitat…", + "components.Settings.RadarrModal.hostname": "Nom de l’amfitrió o adreça IP", + "components.Settings.RadarrModal.externalUrlPlaceholder": "URL extern que apunta al servidor Radarr", + "components.Settings.RadarrModal.defaultserver": "Servidor predeterminat", + "components.Settings.RadarrModal.createradarr": "Afegiu un servidor Radarr nou", + "components.Settings.RadarrModal.add": "Afegeix un servidor", + "components.Settings.Notifications.webhookUrlPlaceholder": "Configuració del servidor → Integracions → Webhooks", + "components.Settings.Notifications.validationSmtpHostRequired": "Heu de proporcionar un nom d’amfitrió o una adreça IP", + "components.Settings.Notifications.validationEmail": "Heu de proporcionar una adreça de correu electrònic vàlida", + "components.Settings.Notifications.validationChatIdRequired": "Heu de proporcionar un identificador de xat vàlid", + "components.Settings.Notifications.validationBotAPIRequired": "Heu de proporcionar un testimoni d'autenticació del bot", + "components.Settings.Notifications.testsent": "S'ha enviat la notificació de prova!", + "components.Settings.Notifications.telegramsettingsfailed": "No s'ha pogut desar la configuració de les notificacions de Telegram.", + "components.Settings.Notifications.ssldisabletip": "L'SSL s'hauria de desactivar a les connexions TLS estàndard (port 587)", + "components.Settings.Notifications.smtpHost": "Amfitrió SMTP", + "components.Settings.Notifications.emailsettingsfailed": "No s'ha pogut desar la configuració de les notificacions per correu electrònic.", + "components.Settings.RadarrModal.apiKey": "Clau API", + "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "Els últims canvis a la branca develop de Overseerr no es mostren a continuació. Vegeu l'historial de pujades d'aquesta branca a GitHub per a més detalls.", + "components.Settings.SettingsAbout.Releases.releases": "Versions", + "components.Settings.SettingsAbout.Releases.releasedataMissing": "La informació de la versió no està disponible. GitHub està fora de línia?", + "components.Settings.SettingsAbout.Releases.latestversion": "Última versió", + "components.Settings.RadarrModal.validationRootFolderRequired": "Heu de seleccionar una carpeta arrel", + "components.Settings.RadarrModal.rootfolder": "Carpeta arrel", + "components.Settings.RadarrModal.qualityprofile": "Perfil de qualitat", + "components.Settings.RadarrModal.preventSearch": "Desactiveu la cerca automàtica", + "components.Settings.RadarrModal.port": "Port", + "components.Settings.RadarrModal.externalUrl": "URL extern", + "components.Settings.RadarrModal.editradarr": "Editeu el servidor Radarr", + "components.Settings.RadarrModal.baseUrlPlaceholder": "Exemple: /radarr", + "components.Settings.RadarrModal.apiKeyPlaceholder": "La vostra clau API de Radarr", + "components.Settings.Notifications.webhookUrl": "URL del Webhook", + "components.Settings.Notifications.validationUrl": "Heu de proporcionar un URL vàlid", + "components.Settings.Notifications.validationSmtpPortRequired": "Heu de proporcionar un número de port vàlid", + "components.Settings.Notifications.telegramsettingssaved": "La configuració de les notificacions de Telegram s'ha desat correctament!", + "components.Settings.Notifications.smtpPort": "Port SMTP", + "components.Settings.Notifications.settinguptelegramDescription": "Per configurar les notificacions de Telegram, haureu de crear un bot i obtenir la clau API del bot. A més, necessitareu l'identificador de xat per al xat al qual voleu enviar notificacions. Podeu fer-ho afegint @get_id_bot al xat i enviant l'ordre / my_id.", + "components.Settings.Notifications.senderName": "Nom de l'emissor", + "components.Settings.Notifications.sendSilentlyTip": "Envia notificacions sense so", + "components.Settings.Notifications.sendSilently": "Envia-ho silenciosament", + "components.Settings.Notifications.pgpPrivateKeyTip": "Signa missatges de correu electrònic xifrats (es requereix contrasenya PGP)", + "components.Settings.Notifications.pgpPrivateKey": "Clau privada PGP", + "components.Settings.Notifications.pgpPasswordTip": "Signa missatges de correu electrònic xifrats (es requereix clau privada PGP)", + "components.Settings.Notifications.pgpPassword": "Contrasenya de PGP", + "components.Settings.Notifications.enableSsl": "Activa SSL", + "components.Settings.Notifications.emailsettingssaved": "La configuració de les notificacions per correu electrònic s'ha desat correctament!", + "components.Settings.Notifications.emailsender": "Adreça de l'emissor", + "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Les notificacions per correu electrònic sobre Mitjans aprovats, Mitjans rebutjats i Mitjans disponibles s'envien a l'usuari que ha enviat la sol·licitud.", + "components.LanguageSelector.originalLanguageDefault": "Tots els idiomes", + "components.LanguageSelector.languageServerDefault": "Predeterminat ({language})", + "components.UserList.userdeleted": "L'usuari s'ha suprimit correctament!", + "components.UserList.usercreatedsuccess": "L'usuari s'ha creat correctament!", + "components.UserList.usercreatedfailed": "S'ha produït un error en crear l'usuari.", + "components.UserList.user": "Usuari", + "components.UserList.totalrequests": "Sol·licituds totals", + "components.UserList.sortUpdated": "Última actualització", + "components.UserList.sortRequests": "Recompte de sol·licituds", + "components.UserList.sortDisplayName": "Nom de visualització", + "components.UserList.sortCreated": "Data de creació", + "components.UserList.role": "Rol", + "components.UserList.plexuser": "Usuari de Plex", + "components.UserList.passwordinfodescription": "Cal configurar i habilitar les notificacions per correu electrònic per generar contrasenyes automàticament.", + "components.UserList.password": "Contrasenya", + "components.UserList.owner": "Propietari", + "components.UserList.nouserstoimport": "No hi ha usuaris nous a importar des de Plex.", + "components.UserList.localuser": "Usuari local", + "components.UserList.lastupdated": "Última actualització", + "components.UserList.importfromplexerror": "S'ha produït un error en importar usuaris de Plex.", + "components.UserList.importfromplex": "Importeu usuaris de Plex", + "components.UserList.importedfromplex": "{userCount, plural, one {# nou usuari} other {# nous usuaris}} importat/s de Plex amb èxit!", + "components.TvDetails.watchtrailer": "Veure el tràiler", + "components.TvDetails.viewfullcrew": "Mostreu equip complet", + "components.TvDetails.similar": "Sèries similars", + "components.TvDetails.showtype": "Tipus de sèrie", + "components.TvDetails.seasons": "{seasonCount, plural, one {# Temporada} other {# Temporades}}", + "components.TvDetails.recommendations": "Recomanacions", + "components.TvDetails.playonplex": "Reprodueix a Plex", + "components.TvDetails.play4konplex": "Reprodueix a Plex en 4K", + "components.Settings.SonarrModal.testFirstTags": "Proveu la connexió per carregar etiquetes", + "components.Settings.SonarrModal.tags": "Etiquetes", + "components.Settings.SonarrModal.selecttags": "Seleccioneu les etiquetes", + "components.Settings.SonarrModal.notagoptions": "Sense etiquetes.", + "components.Settings.SonarrModal.loadingTags": "S'estan carregant les etiquetes…", + "components.Settings.SonarrModal.edit4ksonarr": "Editeu el servidor Sonarr 4K", + "components.Settings.SonarrModal.default4kserver": "Servidor 4K predeterminat", + "components.Settings.SonarrModal.create4ksonarr": "Afegiu un nou servidor Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Etiquetes d'anime", + "components.Settings.RadarrModal.testFirstTags": "Proveu la connexió per carregar etiquetes", + "components.Settings.RadarrModal.tags": "Etiquetes", + "components.Settings.RadarrModal.selecttags": "Seleccioneu les etiquetes", + "components.Settings.RadarrModal.notagoptions": "Sense etiquetes.", + "components.Settings.RadarrModal.loadingTags": "S'estan carregant les etiquetes…", + "components.Settings.RadarrModal.edit4kradarr": "Editeu el servidor Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Servidor 4K predeterminat", + "components.Settings.RadarrModal.create4kradarr": "Afegiu un nou servidor Radarr 4K", + "components.RequestModal.AdvancedRequester.tags": "Etiquetes", + "components.RequestModal.AdvancedRequester.selecttags": "Seleccioneu les etiquetes", + "components.RequestModal.AdvancedRequester.notagoptions": "Sense etiquetes." } diff --git a/src/i18n/locale/de.json b/src/i18n/locale/de.json index 9a51920d..0031d018 100644 --- a/src/i18n/locale/de.json +++ b/src/i18n/locale/de.json @@ -1,7 +1,6 @@ { "components.Discover.discovermovies": "Beliebte Filme", "components.Discover.discovertv": "Beliebte Serien", - "components.Discover.nopending": "Keine ausstehenden Anfragen", "components.Discover.popularmovies": "Beliebte Filme", "components.Discover.populartv": "Beliebte Serien", "components.Discover.recentlyAdded": "Kürzlich hinzugefügt", @@ -16,7 +15,6 @@ "components.Layout.Sidebar.settings": "Einstellungen", "components.Layout.Sidebar.users": "Benutzer", "components.Layout.UserDropdown.signout": "Abmelden", - "components.Layout.alphawarning": "Dies ist eine ALPHA-Software. Funktionen können kaputt und/oder instabil sein. Bitte melde Probleme auf GitHub!", "components.MovieDetails.budget": "Budget", "components.MovieDetails.cast": "Besetzung", "components.MovieDetails.manageModalClearMedia": "Alle Mediendaten löschen", @@ -140,18 +138,15 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "Dienste", "components.Settings.notificationsettings": "Benachrichtigungseinstellungen", - "components.Settings.notificationsettingsDescription": "Konfiguriere globale Benachrichtigungseinstellungen. Diese Einstellungen betreffen alle Benachrichtigungsagenten.", "components.Settings.notrunning": "Nicht aktiv", "components.Settings.plexlibraries": "Plex-Bibliotheken", "components.Settings.plexlibrariesDescription": "Die Bibliotheken, welche Overseerr nach Titeln durchsucht. Richte deine Plex-Verbindungseinstellungen ein und speichere sie, klicke auf die Schaltfläche unten, wenn keine aufgeführt sind.", "components.Settings.plexsettings": "Plex-Einstellungen", "components.Settings.plexsettingsDescription": "Konfiguriere die Einstellungen für deinen Plex-Server. Overseerr durchsucht deine Plex-Bibliotheken, um festzustellen welche Inhalte verfügbar sind.", "components.Settings.port": "Port", - "components.Settings.radarrSettingsDescription": "Konfiguriere unten deine Radarr-Verbindung. Du kannst mehrere Radarr-Konfigurationen haben, aber nur zwei können der Standard sein (eine für Standard-HD und eine für 4K). Administratoren können überschreiben, welcher Server für neue Anfragen verwendet wird.", "components.Settings.radarrsettings": "Radarr-Einstellungen", "components.Settings.servername": "Servername", "components.Settings.servernamePlaceholder": "Plex-Servername", - "components.Settings.sonarrSettingsDescription": "Konfiguriere unten deine Sonarr-Verbindung. Du kannst mehrere Sonarr-Konfigurationen haben, aber nur zwei können der Standard sein (eine für Standard-HD und eine für 4K). Administratoren können überschreiben, welcher Server für neue Anfragen verwendet wird.", "components.Settings.sonarrsettings": "Sonarr-Einstellungen", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Durchsuchung starten", @@ -219,8 +214,6 @@ "components.UserList.userdeleted": "Benutzer erfolgreich gelöscht!", "components.UserList.deleteuser": "Benutzer löschen", "components.UserList.deleteconfirm": "Willst du diesen Benutzer wirklich löschen? Alle vorhandenen Anfragendaten dieses Benutzers werden entfernt.", - "components.Settings.nodefaultdescription": "Mindestens ein Server muss als Standard markiert sein, bevor Anfragen an deine Dienste weitergeleitet werden.", - "components.Settings.nodefault": "Kein Standardserver", "components.Settings.SonarrModal.testFirstRootFolders": "Teste die Verbindung, um Stammordner zu laden", "components.Settings.SonarrModal.testFirstQualityProfiles": "Teste die Verbindung, um Qualitätsprofile zu laden", "components.Settings.SonarrModal.loadingrootfolders": "Stammordner werden geladen …", @@ -248,7 +241,6 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Änderungsprotokoll anzeigen", "components.Settings.SettingsAbout.Releases.versionChangelog": "Änderungsprotokoll", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "Die Änderungen in deiner Version sind unten nicht verfügbar. Die neuesten Aktualisierungen findest du im GitHub-Repository.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Entwicklungsversion", "components.Settings.SettingsAbout.Releases.releases": "Veröffentlichungen", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Informationen der Version nicht verfügbar. Ist GitHub offline?", "components.Settings.SettingsAbout.Releases.latestversion": "Neuste", @@ -281,7 +273,6 @@ "components.Settings.Notifications.NotificationsSlack.testsent": "Testbenachrichtigung gesendet!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slack-Benachrichtigungseinstellungen erfolgreich gespeichert!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack-Benachrichtigungseinstellungen konnten nicht gespeichert werden.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Einrichten von Slack-Benachrichtigungen", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Agent aktivieren", "components.Settings.Notifications.validationChatIdRequired": "Du musst eine gültige Chat-ID angeben", "components.Settings.Notifications.validationBotAPIRequired": "Du musst ein Bot-Authentifizierungstoken angeben", @@ -289,15 +280,12 @@ "components.Settings.Notifications.telegramsettingsfailed": "Telegram-Benachrichtigungseinstellungen konnten nicht gespeichert werden.", "components.Settings.Notifications.senderName": "Absendername", "components.Settings.Notifications.settinguptelegramDescription": "Um Telegram-Benachrichtigungen zu konfigurieren, musst du einen Bot erstellen und den Bot-API-Schlüssel erhalten. Außerdem benötigst du die Chat-ID für den Chat, an den der Bot Benachrichtigungen senden soll. Sie können dies herausfinden, indem Sie dem Chat @get_id_bot hinzufügen und den Befehl /my_id ausgeben.", - "components.Settings.Notifications.settinguptelegram": "Einrichten von Telegram-Benachrichtigungen", "components.Settings.Notifications.chatId": "Chat-ID", "components.Settings.Notifications.botAPI": "Bot-Authentifizierungstoken", "components.StatusChacker.reloadOverseerr": "Overseerr neu laden", "components.StatusChacker.newversionavailable": "Neue Version verfügbar", "components.StatusChacker.newversionDescription": "Eine Aktualisierung ist jetzt verfügbar. Klicke auf die Schaltfläche unten, um die Anwendung neu zu laden.", "components.Settings.SettingsAbout.documentation": "Dokumentation", - "components.Settings.Notifications.notificationtypes": "Benachrichtigungsarten", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Benachrichtigungsarten", "components.NotificationTypeSelector.mediarequestedDescription": "Sendet eine Benachrichtigung, wenn neue Medien angefordert wurden und auf Genehmigung warten.", "components.NotificationTypeSelector.mediarequested": "Medien angefordert", "components.NotificationTypeSelector.mediafailedDescription": "Sendet eine Benachrichtigung, wenn angeforderte Medien nicht zu Radarr oder Sonarr hinzugefügt werden können.", @@ -312,9 +300,7 @@ "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Du musst ein gültiges Anwendungstoken angeben", "components.Settings.Notifications.NotificationsPushover.userToken": "Benutzerschlüssel", "components.Settings.Notifications.NotificationsPushover.testsent": "Test-Benachrichtigung gesendet!", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Einrichten von Pushover-Benachrichtigungen", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover-Benachrichtigungseinstellungen erfolgreich gespeichert!", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Benachrichtigungsarten", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover-Benachrichtigungseinstellungen konnten nicht gespeichert werden.", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Agent aktivieren", "components.Settings.Notifications.NotificationsPushover.accessToken": "Anwendungs-/API-Token", @@ -330,7 +316,6 @@ "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Hilfe zu Vorlagenvariablen", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON-Inhalt erfolgreich zurückgesetzt!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Auf Standard zurücksetzen", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Benachrichtigungsarten", "components.Settings.Notifications.NotificationsWebhook.customJson": "JSON-Inhalt", "components.Settings.Notifications.NotificationsWebhook.authheader": "Autorisierungsüberschrift", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Agent aktivieren", @@ -355,7 +340,6 @@ "components.UserList.usercreatedsuccess": "Benutzer wurde erfolgreich erstellt!", "components.UserList.usercreatedfailed": "Beim Erstellen des Benutzers ist etwas schief gelaufen.", "components.UserList.passwordinfodescription": "E-Mail-Benachrichtigungen müssen eingerichtet und aktiviert sein, um automatische Passwortgeneration benutzen zu können.", - "components.UserList.passwordinfo": "Passwortinformationen", "components.UserList.password": "Passwort", "components.UserList.localuser": "Lokaler Benutzer", "components.UserList.email": "E-Mail-Adresse", @@ -390,17 +374,12 @@ "components.Settings.hideAvailable": "Verfügbare Medien ausblenden", "components.RequestModal.requesterror": "Beim Senden der Anfragen ist etwas schief gelaufen.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Wir konnten deine Anfrage nicht automatisch zuordnen. Bitte wähle eine korrekte Übereinstimmung aus der Liste aus:", - "components.RequestModal.SearchByNameModal.notvdbid": "Manuelle Zuordnung erforderlich", "components.RequestModal.SearchByNameModal.nosummary": "Keine Zusammenfassung für diesen Titel gefunden.", "components.Login.signinwithplex": "Benutze dein Plex-Konto", "components.Login.signinheader": "Anmelden um fortzufahren", "components.Login.signingin": "Anmelden …", "components.Login.signin": "Anmelden", - "components.Settings.notificationsettingsfailed": "Benachrichtigungseinstellungen konnten nicht gespeichert werden.", - "components.Settings.notificationsettingssaved": "Benachrichtigungseinstellungen erfolgreich gespeichert!", - "components.Settings.notificationAgentsSettings": "Benachrichtigungsagenten", "components.Settings.notificationAgentSettingsDescription": "Wähle aus, welche Arten von Benachrichtigungen mit welchen Agenten gesendet werden sollen.", - "components.Settings.enablenotifications": "Aktiviere Benachrichtigungen", "components.PlexLoginButton.signinwithplex": "Anmelden", "components.PlexLoginButton.signingin": "Anmelden …", "components.PermissionEdit.autoapproveSeries": "Automatische Genehmigung von Serien", @@ -422,7 +401,6 @@ "components.Settings.toastPlexConnecting": "Versuche mit Plex zu verbinden …", "components.Settings.settingUpPlexDescription": "Um Plex einzurichten, kannst du deine Daten manuell eintragen oder einen Server auswählen, welcher von plex.tv abgerufen wurde. Drück den Knopf rechts neben dem Dropdown-Menü, um die Verbindung zu überprüfen und verfügbare Server abzurufen.", "components.Settings.servernameTip": "Wird nach dem Speichern automatisch von Plex abgerufen", - "components.Settings.settingUpPlex": "Plex einrichten", "components.Settings.serverpresetRefreshing": "Rufe Server ab …", "components.Settings.serverpresetPlaceholder": "Plex-Server", "components.Settings.serverpresetManualMessage": "Manuelle Konfiguration", @@ -547,7 +525,6 @@ "components.RequestModal.AdvancedRequester.languageprofile": "Sprachprofil", "components.Settings.SettingsJobsCache.process": "Prozess", "components.AppDataWarning.dockerVolumeMissingDescription": "Die {appDataPath} Volume Einbindung wurde nicht korrekt konfiguriert. Alle Daten werden gelöscht, wenn dieser Container gestoppt oder neugestartet wird.", - "components.AppDataWarning.dockerVolumeMissing": "Docker Volume Mount fehlt", "components.Settings.Notifications.sendSilently": "Sende stumm", "components.Settings.Notifications.sendSilentlyTip": "Sende Benachrichtigungen ohne Ton", "components.UserList.sortRequests": "Anzahl der Anfragen", @@ -576,15 +553,12 @@ "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Passwort erfolgreich geändert!", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Beim Passwortändern ist etwas schief gelaufen. Ist dein aktuelles Passwort korrekt?", "components.UserProfile.UserSettings.UserPasswordChange.password": "Passwort", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Dieses Benutzerkonto hat aktuell kein spezifisches Passwort für {applicationTitle}. Konfiguriere unten ein Passwort, um es diesem Konto zu ermöglichen sich als „Lokaler Benutzer“ anzumelden.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Kein Passwort gesetzt", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Neues Passwort", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Aktuelles Passwort", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Passwort bestätigen", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Benachrichtigungseinstellungen erfolgreich gespeichert!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Beim Speichern der Einstellungen ist etwas schief gelaufen.", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Benachrichtigungseinstellungen", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Benachrichtigungen aktivieren", "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord-ID", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Einstellungen erfolgreich gespeichert!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Beim Speichern der Einstellungen ist etwas schief gelaufen.", @@ -599,10 +573,8 @@ "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Du musst ein Zugangstoken angeben", "components.Settings.Notifications.NotificationsPushbullet.testSent": "Test-Benachrichtigung gesendet!", "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Um Pushbullet-Benachrichtigungen zu konfigurieren, musst du ein Zugangstoken erstellen und es unten eingeben.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Einrichten von Pushbullet-Benachrichtigungen", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet-Benachrichtigungseinstellungen erfolgreich gespeichert!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Pushbullet-Benachrichtigungseinstellungen konnten nicht gespeichert werden.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Benachrichtigungsarten", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Agent aktivieren", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Zugangstoken", "components.Layout.UserDropdown.settings": "Einstellungen", @@ -623,7 +595,6 @@ "components.Settings.originallanguageTip": "Filtert Inhalte nach Originalsprache", "components.Settings.email": "E-Mail", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "Bei den Benachrichtigungstypen „Medien angefordert“ und „Medien fehlgeschlagen“ werden Benachrichtigungen nur an Benutzer mit der Berechtigung „Anfragen verwalten“ gesendet.", - "components.Settings.Notifications.emailNotificationTypesAlert": "E-Mail-Benachrichtigungen-Empfänger", "components.RegionSelector.regionDefault": "Alle Regionen", "components.RegionSelector.regionServerDefault": "Standard ({region})", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "Sie haben keine Berechtigung, das Kennwort dieses Benutzers zu ändern.", @@ -639,7 +610,6 @@ "i18n.loading": "Lade …", "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Du musst eine gültige Telegram Chat-ID angeben", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Starte einen Chat, füge @get_id_bot hinzu, und führe den Befehl /my_id aus", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Füge @get_id_bot zum Chat hinzu", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram Chat-ID", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Sende Benachrichtigungen ohne Ton", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Sende Telegramnachrichten ohne Ton", @@ -680,13 +650,11 @@ "components.UserProfile.norequests": "Keine Anfragen", "components.UserProfile.UserSettings.unauthorizedDescription": "Sie haben keine Berechtigung, die Einstellungen dieses Benutzers zu ändern.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "Sie können Ihre eigenen Berechtigungen nicht ändern.", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "E-Mail-Nachrichten verschlüsseln", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP Öffentlicher Schlüssel", "components.TvDetails.episodeRuntimeMinutes": "{runtime} Minuten", "components.TvDetails.episodeRuntime": "Episodenlaufzeit", "components.Settings.partialRequestsEnabled": "Teilserienanforderungen aktivieren", - "components.Settings.Notifications.pgpPrivateKey": "PGP Privater Schlüssel", - "components.Settings.Notifications.pgpPassword": "PGP Passwort", + "components.Settings.Notifications.pgpPrivateKey": "PGP Privater Schlüssel", + "components.Settings.Notifications.pgpPassword": "PGP Passwort", "components.RequestModal.requestall": "Alle Jahreszeiten Anfordern", "components.RequestModal.alreadyrequested": "Bereits Angefragt", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", @@ -705,7 +673,6 @@ "i18n.usersettings": "Benutzereinstellungen", "i18n.settings": "Einstellungen", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Beim Speichern des Passworts ist ein Fehler aufgetreten. Wurde dein aktuelles Passwort korrekt eingegeben?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Dein Konto verfügt derzeit nicht über ein Passwort speziell für {applicationTitle}. Konfiguriere unten ein Passwort, um die Anmeldung als „lokaler Benutzer“ mit deiner E-Mail-Adresse zu aktivieren.", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Benachrichtigungen", "components.UserProfile.UserSettings.UserGeneralSettings.general": "Allgemein", "components.UserList.nouserstoimport": "Keine neuen Benutzer zum Importieren aus Plex.", diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index a0d192d4..60c7ce3e 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -1,5 +1,4 @@ { - "components.AppDataWarning.dockerVolumeMissing": "Docker Volume Mount Missing", "components.AppDataWarning.dockerVolumeMissingDescription": "The {appDataPath} volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.", "components.CollectionDetails.numberofmovies": "{count} Movies", "components.CollectionDetails.overview": "Overview", @@ -23,7 +22,7 @@ "components.Discover.discover": "Discover", "components.Discover.discovermovies": "Popular Movies", "components.Discover.discovertv": "Popular Series", - "components.Discover.nopending": "No Pending Requests", + "components.Discover.noRequests": "No requests.", "components.Discover.popularmovies": "Popular Movies", "components.Discover.populartv": "Popular Series", "components.Discover.recentlyAdded": "Recently Added", @@ -43,7 +42,11 @@ "components.Layout.UserDropdown.myprofile": "Profile", "components.Layout.UserDropdown.settings": "Settings", "components.Layout.UserDropdown.signout": "Sign Out", - "components.Layout.alphawarning": "This is ALPHA software. Features may be broken and/or unstable. Please report any issues on GitHub!", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind", + "components.Layout.VersionStatus.outofdate": "Out of Date", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Develop", + "components.Layout.VersionStatus.streamstable": "Overseerr Stable", + "components.Layout.betawarning": "This is BETA software. Features may be broken and/or unstable. Please report any issues on GitHub!", "components.Login.email": "Email Address", "components.Login.forgotpassword": "Forgot Password?", "components.Login.loginerror": "Something went wrong while trying to sign in.", @@ -63,7 +66,7 @@ "components.MovieDetails.downloadstatus": "Download Status", "components.MovieDetails.manageModalClearMedia": "Clear All Media Data", "components.MovieDetails.manageModalClearMediaWarning": "* This will irreversibly remove all data for this movie, including any requests. If this item exists in your Plex library, the media information will be recreated during the next scan.", - "components.MovieDetails.manageModalNoRequests": "No Requests", + "components.MovieDetails.manageModalNoRequests": "No requests.", "components.MovieDetails.manageModalRequests": "Requests", "components.MovieDetails.manageModalTitle": "Manage Movie", "components.MovieDetails.mark4kavailable": "Mark 4K as Available", @@ -96,6 +99,7 @@ "components.NotificationTypeSelector.mediafailedDescription": "Sends a notification when requested media fails to be added to Radarr or Sonarr.", "components.NotificationTypeSelector.mediarequested": "Media Requested", "components.NotificationTypeSelector.mediarequestedDescription": "Sends a notification when media is requested and requires approval.", + "components.NotificationTypeSelector.notificationTypes": "Notification Types", "components.PermissionEdit.admin": "Admin", "components.PermissionEdit.adminDescription": "Full administrator access. Bypasses all other permission checks.", "components.PermissionEdit.advancedrequest": "Advanced Requests", @@ -160,8 +164,13 @@ "components.RequestButton.requestmore4k": "Request More 4K", "components.RequestButton.viewrequest": "View Request", "components.RequestButton.viewrequest4k": "View 4K Request", + "components.RequestCard.deleterequest": "Delete Request", + "components.RequestCard.mediaerror": "The associated title for this request is no longer available.", "components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}", + "components.RequestList.RequestItem.cancelRequest": "Cancel Request", + "components.RequestList.RequestItem.deleterequest": "Delete Request", "components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.", + "components.RequestList.RequestItem.mediaerror": "The associated title for this request is no longer available.", "components.RequestList.RequestItem.modified": "Modified", "components.RequestList.RequestItem.modifieduserdate": "{date} by {user}", "components.RequestList.RequestItem.requested": "Requested", @@ -176,9 +185,12 @@ "components.RequestModal.AdvancedRequester.destinationserver": "Destination Server", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.RequestModal.AdvancedRequester.languageprofile": "Language Profile", + "components.RequestModal.AdvancedRequester.notagoptions": "No tags.", "components.RequestModal.AdvancedRequester.qualityprofile": "Quality Profile", "components.RequestModal.AdvancedRequester.requestas": "Request As", "components.RequestModal.AdvancedRequester.rootfolder": "Root Folder", + "components.RequestModal.AdvancedRequester.selecttags": "Select tags", + "components.RequestModal.AdvancedRequester.tags": "Tags", "components.RequestModal.QuotaDisplay.allowedRequests": "You are allowed to request {limit} {type} every {days} days.", "components.RequestModal.QuotaDisplay.allowedRequestsUser": "This user is allowed to request {limit} {type} every {days} days.", "components.RequestModal.QuotaDisplay.movie": "movie", @@ -192,7 +204,6 @@ "components.RequestModal.QuotaDisplay.season": "season", "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {season} other {seasons}}", "components.RequestModal.SearchByNameModal.nosummary": "No summary for this title was found.", - "components.RequestModal.SearchByNameModal.notvdbid": "Manual Match Required", "components.RequestModal.SearchByNameModal.notvdbiddescription": "We couldn't automatically match your request. Please select the correct match from the list below.", "components.RequestModal.alreadyrequested": "Already Requested", "components.RequestModal.autoapproval": "Automatic Approval", @@ -201,6 +212,7 @@ "components.RequestModal.extras": "Extras", "components.RequestModal.numberofepisodes": "# of Episodes", "components.RequestModal.pending4krequest": "Pending Request for {title} in 4K", + "components.RequestModal.pendingapproval": "Your request is pending approval.", "components.RequestModal.pendingrequest": "Pending Request for {title}", "components.RequestModal.request4kfrom": "There is currently a pending 4K request from {username}.", "components.RequestModal.request4ktitle": "Request {title} in 4K", @@ -234,41 +246,34 @@ "components.Search.searchresults": "Search Results", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Access Token", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Enable Agent", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Notification Types", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Pushbullet notification settings failed to save.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet notification settings saved successfully!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Setting Up Pushbullet Notifications", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "To configure Pushbullet notifications, you will need to create an access token and enter it below.", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Test notification sent!", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "To configure Pushbullet notifications, you will need to create an access token.", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Pushbullet test notification sent!", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "You must provide an access token", "components.Settings.Notifications.NotificationsPushover.accessToken": "Application/API Token", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Enable Agent", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Notification Types", "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.settinguppushover": "Setting Up Pushover Notifications", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "To configure Pushover notifications, you will need to register an application and enter the API token below. (You can use one of our official icons on GitHub.) You will also need your user key.", - "components.Settings.Notifications.NotificationsPushover.testsent": "Test notification sent!", - "components.Settings.Notifications.NotificationsPushover.userToken": "User Key", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "To configure Pushover notifications, you will need to register an application and enter the API token below. (You can use one of the official Overseerr icons on GitHub.)", + "components.Settings.Notifications.NotificationsPushover.testsent": "Pushover test notification sent!", + "components.Settings.Notifications.NotificationsPushover.userToken": "User or Group Key", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "You must provide a valid application token", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "You must provide a valid user key", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Enable Agent", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Notification Types", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Setting Up Slack Notifications", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "To configure Slack notifications, you will need to create an Incoming Webhook integration and enter the webhook URL below.", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack notification settings failed to save.", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slack notification settings saved successfully!", - "components.Settings.Notifications.NotificationsSlack.testsent": "Test notification sent!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Slack test notification sent!", "components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "You must provide a valid URL", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Enable Agent", "components.Settings.Notifications.NotificationsWebhook.authheader": "Authorization Header", "components.Settings.Notifications.NotificationsWebhook.customJson": "JSON Payload", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Notification Types", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Reset to Default", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON payload reset successfully!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Template Variable Help", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Test notification sent!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Webhook test notification sent!", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "You must provide a valid JSON payload", "components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "You must provide a valid URL", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "Webhook URL", @@ -281,36 +286,36 @@ "components.Settings.Notifications.botAPI": "Bot Authentication Token", "components.Settings.Notifications.botAvatarUrl": "Bot Avatar URL", "components.Settings.Notifications.botUsername": "Bot Username", + "components.Settings.Notifications.botUsernameTip": "Allow users to start a chat with the bot and configure their own personal notifications", "components.Settings.Notifications.chatId": "Chat ID", "components.Settings.Notifications.discordsettingsfailed": "Discord notification settings failed to save.", "components.Settings.Notifications.discordsettingssaved": "Discord notification settings saved successfully!", - "components.Settings.Notifications.emailNotificationTypesAlert": "Email Notification Recipients", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "Media Requested, Media Automatically Approved, and Media Failed email notifications are sent to all users with the Manage Requests permission.", "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Media Approved, Media Declined, and Media Available email notifications are sent to the user who submitted the request.", "components.Settings.Notifications.emailsender": "Sender Address", "components.Settings.Notifications.emailsettingsfailed": "Email notification settings failed to save.", "components.Settings.Notifications.emailsettingssaved": "Email notification settings saved successfully!", "components.Settings.Notifications.enableSsl": "Enable SSL", - "components.Settings.Notifications.notificationtypes": "Notification Types", - "components.Settings.Notifications.pgpPassword": "PGP Password", - "components.Settings.Notifications.pgpPasswordTip": "Sign encrypted email messages (PGP private key is also required)", - "components.Settings.Notifications.pgpPrivateKey": "PGP Private Key", - "components.Settings.Notifications.pgpPrivateKeyTip": "Sign encrypted email messages (PGP password is also required)", + "components.Settings.Notifications.pgpPassword": "PGP Password", + "components.Settings.Notifications.pgpPasswordTip": "Sign encrypted email messages using OpenPGP", + "components.Settings.Notifications.pgpPrivateKey": "PGP Private Key", + "components.Settings.Notifications.pgpPrivateKeyTip": "Sign encrypted email messages using OpenPGP", "components.Settings.Notifications.sendSilently": "Send Silently", "components.Settings.Notifications.sendSilentlyTip": "Send notifications with no sound", "components.Settings.Notifications.senderName": "Sender Name", - "components.Settings.Notifications.settinguptelegram": "Setting Up Telegram Notifications", "components.Settings.Notifications.settinguptelegramDescription": "To configure Telegram notifications, you will need to create a bot and get the bot API key. Additionally, you will need the chat ID for the chat to which you would like to send notifications. You can find this by adding @get_id_bot to the chat and issuing the /my_id command.", "components.Settings.Notifications.smtpHost": "SMTP Host", "components.Settings.Notifications.smtpPort": "SMTP Port", "components.Settings.Notifications.ssldisabletip": "SSL should be disabled on standard TLS connections (port 587)", "components.Settings.Notifications.telegramsettingsfailed": "Telegram notification settings failed to save.", "components.Settings.Notifications.telegramsettingssaved": "Telegram notification settings saved successfully!", - "components.Settings.Notifications.testsent": "Test notification sent!", + "components.Settings.Notifications.testsent": "Telegram test notification sent!", "components.Settings.Notifications.validationBotAPIRequired": "You must provide a bot authentication token", "components.Settings.Notifications.validationChatIdRequired": "You must provide a valid chat ID", "components.Settings.Notifications.validationEmail": "You must provide a valid email address", - "components.Settings.Notifications.validationSmtpHostRequired": "You must provide a hostname or IP address", + "components.Settings.Notifications.validationPgpPassword": "You must provide a PGP password if a PGP private key is entered", + "components.Settings.Notifications.validationPgpPrivateKey": "You must provide a valid PGP private key if a PGP password is entered", + "components.Settings.Notifications.validationSmtpHostRequired": "You must provide a valid hostname or IP address", "components.Settings.Notifications.validationSmtpPortRequired": "You must provide a valid port number", "components.Settings.Notifications.validationUrl": "You must provide a valid URL", "components.Settings.Notifications.webhookUrl": "Webhook URL", @@ -320,15 +325,20 @@ "components.Settings.RadarrModal.apiKeyPlaceholder": "Your Radarr API key", "components.Settings.RadarrModal.baseUrl": "Base URL", "components.Settings.RadarrModal.baseUrlPlaceholder": "Example: /radarr", + "components.Settings.RadarrModal.create4kradarr": "Add New 4K Radarr Server", "components.Settings.RadarrModal.createradarr": "Add New Radarr Server", + "components.Settings.RadarrModal.default4kserver": "Default 4K Server", "components.Settings.RadarrModal.defaultserver": "Default Server", + "components.Settings.RadarrModal.edit4kradarr": "Edit 4K Radarr Server", "components.Settings.RadarrModal.editradarr": "Edit Radarr Server", "components.Settings.RadarrModal.externalUrl": "External URL", "components.Settings.RadarrModal.externalUrlPlaceholder": "External URL pointing to your Radarr server", "components.Settings.RadarrModal.hostname": "Hostname or IP Address", + "components.Settings.RadarrModal.loadingTags": "Loading tags…", "components.Settings.RadarrModal.loadingprofiles": "Loading quality profiles…", "components.Settings.RadarrModal.loadingrootfolders": "Loading root folders…", "components.Settings.RadarrModal.minimumAvailability": "Minimum Availability", + "components.Settings.RadarrModal.notagoptions": "No tags.", "components.Settings.RadarrModal.port": "Port", "components.Settings.RadarrModal.preventSearch": "Disable Auto-Search", "components.Settings.RadarrModal.qualityprofile": "Quality Profile", @@ -336,13 +346,16 @@ "components.Settings.RadarrModal.selectMinimumAvailability": "Select minimum availability", "components.Settings.RadarrModal.selectQualityProfile": "Select quality profile", "components.Settings.RadarrModal.selectRootFolder": "Select root folder", + "components.Settings.RadarrModal.selecttags": "Select tags", "components.Settings.RadarrModal.server4k": "4K Server", "components.Settings.RadarrModal.servername": "Server Name", "components.Settings.RadarrModal.servernamePlaceholder": "A Radarr Server", "components.Settings.RadarrModal.ssl": "Enable SSL", "components.Settings.RadarrModal.syncEnabled": "Enable Scan", + "components.Settings.RadarrModal.tags": "Tags", "components.Settings.RadarrModal.testFirstQualityProfiles": "Test connection to load quality profiles", "components.Settings.RadarrModal.testFirstRootFolders": "Test connection to load root folders", + "components.Settings.RadarrModal.testFirstTags": "Test connection to load tags", "components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.", "components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established successfully!", "components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key", @@ -360,7 +373,6 @@ "components.Settings.SettingsAbout.Releases.latestversion": "Latest", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Release data unavailable. Is GitHub down?", "components.Settings.SettingsAbout.Releases.releases": "Releases", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Development Version", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "The latest changes to the develop branch of Overseerr are not shown below. Please see the commit history for this branch on GitHub for details.", "components.Settings.SettingsAbout.Releases.versionChangelog": "Version Changelog", "components.Settings.SettingsAbout.Releases.viewchangelog": "View Changelog", @@ -370,12 +382,14 @@ "components.Settings.SettingsAbout.gettingsupport": "Getting Support", "components.Settings.SettingsAbout.githubdiscussions": "GitHub Discussions", "components.Settings.SettingsAbout.helppaycoffee": "Help Pay for Coffee", + "components.Settings.SettingsAbout.outofdate": "Out of Date", "components.Settings.SettingsAbout.overseerrinformation": "Overseerr Information", "components.Settings.SettingsAbout.preferredmethod": "Preferred", "components.Settings.SettingsAbout.supportoverseerr": "Support Overseerr", "components.Settings.SettingsAbout.timezone": "Time Zone", "components.Settings.SettingsAbout.totalmedia": "Total Media", "components.Settings.SettingsAbout.totalrequests": "Total Requests", + "components.Settings.SettingsAbout.uptodate": "Up to Date", "components.Settings.SettingsAbout.version": "Version", "components.Settings.SettingsJobsCache.cache": "Cache", "components.Settings.SettingsJobsCache.cacheDescription": "Overseerr caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls.", @@ -433,6 +447,7 @@ "components.Settings.SettingsUsers.userSettingsDescription": "Configure global and default user settings.", "components.Settings.SettingsUsers.users": "Users", "components.Settings.SonarrModal.add": "Add Server", + "components.Settings.SonarrModal.animeTags": "Anime Tags", "components.Settings.SonarrModal.animelanguageprofile": "Anime Language Profile", "components.Settings.SonarrModal.animequalityprofile": "Anime Quality Profile", "components.Settings.SonarrModal.animerootfolder": "Anime Root Folder", @@ -440,16 +455,21 @@ "components.Settings.SonarrModal.apiKeyPlaceholder": "Your Sonarr API key", "components.Settings.SonarrModal.baseUrl": "Base URL", "components.Settings.SonarrModal.baseUrlPlaceholder": "Example: /sonarr", + "components.Settings.SonarrModal.create4ksonarr": "Add New 4K Sonarr Server", "components.Settings.SonarrModal.createsonarr": "Add New Sonarr Server", + "components.Settings.SonarrModal.default4kserver": "Default 4K Server", "components.Settings.SonarrModal.defaultserver": "Default Server", + "components.Settings.SonarrModal.edit4ksonarr": "Edit 4K Sonarr Server", "components.Settings.SonarrModal.editsonarr": "Edit Sonarr Server", "components.Settings.SonarrModal.externalUrl": "External URL", "components.Settings.SonarrModal.externalUrlPlaceholder": "External URL pointing to your Sonarr server", "components.Settings.SonarrModal.hostname": "Hostname or IP Address", "components.Settings.SonarrModal.languageprofile": "Language Profile", + "components.Settings.SonarrModal.loadingTags": "Loading tags…", "components.Settings.SonarrModal.loadinglanguageprofiles": "Loading language profiles…", "components.Settings.SonarrModal.loadingprofiles": "Loading quality profiles…", "components.Settings.SonarrModal.loadingrootfolders": "Loading root folders…", + "components.Settings.SonarrModal.notagoptions": "No tags.", "components.Settings.SonarrModal.port": "Port", "components.Settings.SonarrModal.preventSearch": "Disable Auto-Search", "components.Settings.SonarrModal.qualityprofile": "Quality Profile", @@ -458,14 +478,17 @@ "components.Settings.SonarrModal.selectLanguageProfile": "Select language profile", "components.Settings.SonarrModal.selectQualityProfile": "Select quality profile", "components.Settings.SonarrModal.selectRootFolder": "Select root folder", + "components.Settings.SonarrModal.selecttags": "Select tags", "components.Settings.SonarrModal.server4k": "4K Server", "components.Settings.SonarrModal.servername": "Server Name", "components.Settings.SonarrModal.servernamePlaceholder": "A Sonarr Server", "components.Settings.SonarrModal.ssl": "Enable SSL", "components.Settings.SonarrModal.syncEnabled": "Enable Scan", + "components.Settings.SonarrModal.tags": "Tags", "components.Settings.SonarrModal.testFirstLanguageProfiles": "Test connection to load language profiles", "components.Settings.SonarrModal.testFirstQualityProfiles": "Test connection to load quality profiles", "components.Settings.SonarrModal.testFirstRootFolders": "Test connection to load root folders", + "components.Settings.SonarrModal.testFirstTags": "Test connection to load tags", "components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.", "components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established successfully!", "components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key", @@ -498,7 +521,6 @@ "components.Settings.default4k": "Default 4K", "components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?", "components.Settings.email": "Email", - "components.Settings.enablenotifications": "Enable Notifications", "components.Settings.enablessl": "Enable SSL", "components.Settings.general": "General", "components.Settings.generalsettings": "General Settings", @@ -508,6 +530,8 @@ "components.Settings.librariesRemaining": "Libraries Remaining: {count}", "components.Settings.manualscan": "Manual Library Scan", "components.Settings.manualscanDescription": "Normally, this will only be run once every 24 hours. Overseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!", + "components.Settings.mediaTypeMovie": "movie", + "components.Settings.mediaTypeSeries": "series", "components.Settings.menuAbout": "About", "components.Settings.menuGeneralSettings": "General", "components.Settings.menuJobs": "Jobs & Cache", @@ -516,15 +540,11 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "Services", "components.Settings.menuUsers": "Users", - "components.Settings.nodefault": "No Default Server", - "components.Settings.nodefaultdescription": "At least one server must be marked as default before any requests will make it to your services.", - "components.Settings.notificationAgentSettingsDescription": "Choose the types of notifications to send, and which notification agents to use.", - "components.Settings.notificationAgentsSettings": "Notification Agents", + "components.Settings.noDefaultNon4kServer": "If you only have a single {serverType} server for both non-4K and 4K content (or if you only download 4K content), your {serverType} server should NOT be designated as a 4K server.", + "components.Settings.noDefaultServer": "At least one {serverType} server must be marked as default in order for {mediaType} requests to be processed.", + "components.Settings.notificationAgentSettingsDescription": "Configure and enable notification agents.", "components.Settings.notifications": "Notifications", "components.Settings.notificationsettings": "Notification Settings", - "components.Settings.notificationsettingsDescription": "Configure global notification settings. The options below will apply to all notification agents.", - "components.Settings.notificationsettingsfailed": "Notification settings failed to save.", - "components.Settings.notificationsettingssaved": "Notification settings saved successfully!", "components.Settings.notrunning": "Not Running", "components.Settings.originallanguage": "Discover Language", "components.Settings.originallanguageTip": "Filter content by original language", @@ -535,7 +555,6 @@ "components.Settings.plexsettings": "Plex Settings", "components.Settings.plexsettingsDescription": "Configure the settings for your Plex server. Overseerr scans your Plex libraries to see what content is available.", "components.Settings.port": "Port", - "components.Settings.radarrSettingsDescription": "Configure your Radarr connection below. You can have multiple Radarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.", "components.Settings.radarrsettings": "Radarr Settings", "components.Settings.region": "Discover Region", "components.Settings.regionTip": "Filter content by regional availability", @@ -552,10 +571,9 @@ "components.Settings.serverpresetManualMessage": "Manual configuration", "components.Settings.serverpresetPlaceholder": "Plex Server", "components.Settings.serverpresetRefreshing": "Retrieving servers…", + "components.Settings.serviceSettingsDescription": "Configure your {serverType} server(s) below. You can connect multiple {serverType} servers, but only two of them can be marked as defaults (one non-4K and one 4K). Administrators are able to override the server used to process new requests prior to approval.", "components.Settings.services": "Services", - "components.Settings.settingUpPlex": "Setting Up Plex", - "components.Settings.settingUpPlexDescription": "To set up Plex, you can either enter your details manually or select a server retrieved from plex.tv. Press the button to the right of the dropdown to check connectivity and retrieve available servers.", - "components.Settings.sonarrSettingsDescription": "Configure your Sonarr connection below. You can have multiple Sonarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.", + "components.Settings.settingUpPlexDescription": "To set up Plex, you can either enter your details manually or select a server retrieved from plex.tv. Press the button to the right of the dropdown to fetch the list of available servers.", "components.Settings.sonarrsettings": "Sonarr Settings", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Start Scan", @@ -604,7 +622,7 @@ "components.TvDetails.firstAirDate": "First Air Date", "components.TvDetails.manageModalClearMedia": "Clear All Media Data", "components.TvDetails.manageModalClearMediaWarning": "* This will irreversibly remove all data for this TV series, including any requests. If this item exists in your Plex library, the media information will be recreated during the next scan.", - "components.TvDetails.manageModalNoRequests": "No Requests", + "components.TvDetails.manageModalNoRequests": "No requests.", "components.TvDetails.manageModalRequests": "Requests", "components.TvDetails.manageModalTitle": "Manage Series", "components.TvDetails.mark4kavailable": "Mark 4K as Available", @@ -627,14 +645,15 @@ "components.TvDetails.watchtrailer": "Watch Trailer", "components.UserList.accounttype": "Account Type", "components.UserList.admin": "Admin", - "components.UserList.autogeneratepassword": "Automatically generate password", + "components.UserList.autogeneratepassword": "Automatically Generate Password", + "components.UserList.autogeneratepasswordTip": "Email a server-generated password to the user", "components.UserList.bulkedit": "Bulk Edit", "components.UserList.create": "Create", "components.UserList.created": "Created", "components.UserList.createlocaluser": "Create Local User", "components.UserList.createuser": "Create User", "components.UserList.creating": "Creating…", - "components.UserList.deleteconfirm": "Are you sure you want to delete this user? All existing request data from this user will be removed.", + "components.UserList.deleteconfirm": "Are you sure you want to delete this user? All of their request data will be permanently removed.", "components.UserList.deleteuser": "Delete User", "components.UserList.edituser": "Edit User Permissions", "components.UserList.email": "Email Address", @@ -646,8 +665,7 @@ "components.UserList.nouserstoimport": "No new users to import from Plex.", "components.UserList.owner": "Owner", "components.UserList.password": "Password", - "components.UserList.passwordinfo": "Password Information", - "components.UserList.passwordinfodescription": "Email notifications need to be configured and enabled in order to automatically generate passwords.", + "components.UserList.passwordinfodescription": "Enable email notifications to allow automatic password generation.", "components.UserList.plexuser": "Plex User", "components.UserList.role": "Role", "components.UserList.sortCreated": "Creation Date", @@ -689,28 +707,36 @@ "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Something went wrong while saving settings.", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!", "components.UserProfile.UserSettings.UserGeneralSettings.user": "User", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord ID", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The ID number for your Discord user account", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Enable Notifications", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The ID number for your user account", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Discord notification settings failed to save.", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Discord notification settings saved successfully!", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "Email", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Email notification settings failed to save.", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Email notification settings saved successfully!", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Enable Mentions", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Enable Notifications", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Enable Notifications", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notifications", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Notification Settings", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP Public Key", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Encrypt email messages", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Telegram Messages Silently", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "PGP Public Key", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Encrypt email messages using OpenPGP", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Silently", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram Chat ID", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Add @get_id_bot to the chat", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat ID", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Start a chat, add @get_id_bot, and issue the /my_id command", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram notification settings failed to save.", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Telegram notification settings saved successfully!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Something went wrong while saving settings.", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Notification settings saved successfully!", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "You must provide a valid Discord user ID", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid Telegram chat ID", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "You must provide a valid user ID", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "You must provide a valid PGP public key", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid chat ID", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirm Password", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Current Password", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "New Password", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "No Password Set", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a \"local user.\"", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a \"local user\" using your email address.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "This user account currently does not have a password set. Configure a password below to enable this account to sign in as a \"local user.\"", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Your account currently does not have a password set. Configure a password below to enable sign-in as a \"local user\" using your email address.", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "You do not have permission to modify this user's password.", "components.UserProfile.UserSettings.UserPasswordChange.password": "Password", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Something went wrong while saving the password.", @@ -732,7 +758,7 @@ "components.UserProfile.UserSettings.unauthorizedDescription": "You do not have permission to modify this user's settings.", "components.UserProfile.limit": "{remaining} of {limit}", "components.UserProfile.movierequests": "Movie Requests", - "components.UserProfile.norequests": "No Requests", + "components.UserProfile.norequests": "No requests.", "components.UserProfile.pastdays": "{type} (past {days} days)", "components.UserProfile.recentrequests": "Recent Requests", "components.UserProfile.requestsperdays": "{limit} remaining", @@ -782,7 +808,6 @@ "i18n.testing": "Testing…", "i18n.tvshow": "Series", "i18n.tvshows": "Series", - "i18n.unauthorized": "Unauthorized", "i18n.unavailable": "Unavailable", "i18n.usersettings": "User Settings", "i18n.view": "View", diff --git a/src/i18n/locale/es.json b/src/i18n/locale/es.json index 50081c8c..0421b40e 100644 --- a/src/i18n/locale/es.json +++ b/src/i18n/locale/es.json @@ -55,7 +55,7 @@ "components.Settings.Notifications.webhookUrlPlaceholder": "Ajustes del Servidor → Integraciones → Webhooks", "components.Settings.Notifications.webhookUrl": "URL de Webhook", "components.Settings.Notifications.validationSmtpPortRequired": "Debes proporcionar un número de puerto válido", - "components.Settings.Notifications.validationSmtpHostRequired": "Debes proporcionar un nombre de host o una dirección IP", + "components.Settings.Notifications.validationSmtpHostRequired": "Debes proporcionar un nombre válido de host o una dirección IP", "components.Settings.Notifications.smtpPort": "Puerto SMTP", "components.Settings.Notifications.smtpHost": "Host SMTP", "components.Settings.Notifications.enableSsl": "Activar SSL", @@ -72,7 +72,7 @@ "components.RequestModal.seasonnumber": "Temporada {number}", "components.RequestModal.season": "Temporada", "components.RequestModal.requesttitle": "Solicitar {title}", - "components.RequestModal.requestseasons": "Solicitar {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}", + "components.RequestModal.requestseasons": "Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}", "components.RequestModal.requestfrom": "Hay una petición pendiente de {username}.", "components.RequestModal.requestadmin": "Esta petición será aprobada automáticamente.", "components.RequestModal.requestSuccess": "¡{title} solicitada on éxito!", @@ -86,7 +86,7 @@ "components.RequestCard.seasons": "{seasonCount, plural, one {Temporada} other {Temporadas}}", "components.RequestBlock.seasons": "{seasonCount, plural, one {Temporada} other {Temporadas}}", "components.PersonDetails.ascharacter": "como {character}", - "components.PersonDetails.appearsin": "Apariencias", + "components.PersonDetails.appearsin": "Apariciones", "components.MovieDetails.similar": "Títulos Similares", "components.MovieDetails.runtime": "{minutes} minutos", "components.MovieDetails.revenue": "Recaudado", @@ -99,7 +99,7 @@ "components.MovieDetails.originallanguage": "Idioma Original", "components.MovieDetails.manageModalTitle": "Gestionar Película", "components.MovieDetails.manageModalRequests": "Peticiones", - "components.MovieDetails.manageModalNoRequests": "Sin Peticiones", + "components.MovieDetails.manageModalNoRequests": "Sin peticiones.", "components.MovieDetails.manageModalClearMediaWarning": "* Esto borrará todos los datos de esta película, incluyendo las peticiones. Si el elemento existe en tu librería de Plex, la información del elemento se recreará en el siguiente escaneo.", "components.MovieDetails.manageModalClearMedia": "Borrar todos los datos de medios", "components.MovieDetails.budget": "Presupuesto", @@ -117,10 +117,8 @@ "components.Discover.recentlyAdded": "Agregado Recientemente", "components.Discover.populartv": "Series Populares", "components.Discover.popularmovies": "Películas Populares", - "components.Discover.nopending": "Sin Peticiones Pendientes", "components.Discover.discovertv": "Series Populares", "components.Discover.discovermovies": "Películas Populares", - "components.Layout.alphawarning": "Este software está en fase ALFA. Muchas funcionalidades pueden ser inestables o fallar. ¡Por favor reporta estos problemas en el GitHub de Overseerr!", "components.Settings.addsonarr": "Agregar servidor Sonarr", "components.Settings.address": "Dirección", "components.Settings.addradarr": "Agregar servidor Radarr", @@ -155,14 +153,14 @@ "components.UserList.lastupdated": "Última actualización", "components.UserList.created": "Creado", "components.UserList.admin": "Administrador", - "components.TvDetails.similar": "Series similares", + "components.TvDetails.similar": "Series Similares", "components.TvDetails.recommendations": "Recomendaciones", "components.TvDetails.overviewunavailable": "Resumen indisponible.", "components.TvDetails.overview": "Resumen", "components.TvDetails.originallanguage": "Idioma original", "components.TvDetails.manageModalTitle": "Gestionar Series", "components.TvDetails.manageModalRequests": "Peticiones", - "components.TvDetails.manageModalNoRequests": "Sin Peticiones", + "components.TvDetails.manageModalNoRequests": "Sin peticiones.", "components.TvDetails.manageModalClearMediaWarning": "* Esto borrará de forma irreversible todos los datos de las series de TV, incluyendo las peticiones. Si el elemento existe en tu librería de Plex, la información del elemento se recreará en el siguiente escaneo.", "components.TvDetails.manageModalClearMedia": "Borrar todos los datos de medios", "components.TvDetails.cast": "Reparto", @@ -180,18 +178,15 @@ "components.Settings.startscan": "Iniciar Escaneo", "components.Settings.ssl": "SSL", "components.Settings.sonarrsettings": "Ajustes de Sonarr", - "components.Settings.sonarrSettingsDescription": "Configure su conexión Sonarr a continuación. Puede tener varias configuraciones de Sonarr, pero sólo se permiten dos activas como predeterminadas en cualquier momento (una para HD estándar y otro para 4K). Los administradores pueden modificar el servidor que se utiliza para nuevas solicitudes.", "components.Settings.servernamePlaceholder": "Nombre del servidor Plex", "components.Settings.servername": "Nombre del Servidor", "components.Settings.radarrsettings": "Ajustes de Radarr", - "components.Settings.radarrSettingsDescription": "Configure su conexión a Radarr a continuación. Puede tener varias configuraciones de Radarr, pero sólo se permiten dos activas como predeterminadas en cualquier momento (una para HD estándar y otra para 4K). Los administradores pueden modificar el servidor que se utiliza para nuevas solicitudes.", "components.Settings.port": "Puerto", "components.Settings.plexsettingsDescription": "Configure los ajustes de su servidor Plex. Overseerr escanea tu biblioteca para ver qué contenido está disponible.", "components.Settings.plexsettings": "Ajustes de Plex", "components.Settings.plexlibrariesDescription": "Las bibliotecas en las que Overseerr escanea para buscar títulos. Configure y guarde la configuración de conexión Plex, y después haga clic en el botón de abajo si no aparece ninguna.", "components.Settings.plexlibraries": "Bibliotecas Plex", "components.Settings.notrunning": "Sin ejecutarse", - "components.Settings.notificationsettingsDescription": "Configurar ajustes globales de notificaciones. Las opciones a continuación aplicará a todos los agentes de notificaciones.", "components.Settings.notificationsettings": "Configuración de notificaciones", "components.Settings.menuServices": "Servicios", "components.Settings.menuPlexSettings": "Plex", @@ -218,9 +213,7 @@ "components.UserList.userdeleteerror": "Algo salió mal al eliminar al usuario.", "components.UserList.userdeleted": "¡Usuario eliminado con éxito!", "components.UserList.deleteuser": "Eliminar usuario", - "components.UserList.deleteconfirm": "¿Está seguro de que desea eliminar este usuario? Se eliminarán todas las solicitudes existentes de este usuario.", - "components.Settings.nodefaultdescription": "Al menos un servidor debe estar marcado como predeterminado antes de que cualquier solicitud llegue a sus servicios.", - "components.Settings.nodefault": "Ningún servidor predeterminado seleccionado", + "components.UserList.deleteconfirm": "¿Está seguro de que desea eliminar este usuario? Se eliminarán todas sus solicitudes de forma permanente.", "components.Settings.SonarrModal.testFirstRootFolders": "Probar conexión para cargar carpetas raíz", "components.Settings.SonarrModal.testFirstQualityProfiles": "Probar conexión para cargar perfiles de calidad", "components.Settings.SonarrModal.loadingrootfolders": "Cargando carpetas raíz…", @@ -247,12 +240,11 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Ver registro de cambios", "components.Settings.SettingsAbout.Releases.versionChangelog": "Cambios de la versión", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "Los últimos cambios de la rama de desarrollo de Overserr no se muestran a continuación. Por favor, consulta la historia de subidas de esta rama en GitHub para obtener los detalles.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Versión de Desarrollo", "components.Settings.SettingsAbout.Releases.releases": "Versiones", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Información de la versión no disponible. ¿GitHub está caído?", "components.Settings.SettingsAbout.Releases.latestversion": "Última Versión", "components.Settings.SettingsAbout.Releases.currentversion": "Versión Actual", - "components.Settings.Notifications.testsent": "¡Notificación de prueba enviada!", + "components.Settings.Notifications.testsent": "¡Notificación de prueba de Telegram enviada!", "components.MovieDetails.studio": "{studioCount, plural, one {Estudio} other {Estudios}}", "components.UserList.importfromplexerror": "Algo salió mal importando usuarios de Plex.", "components.UserList.importfromplex": "Importar Usuarios de Plex", @@ -275,11 +267,10 @@ "i18n.failed": "Fallido", "components.TvDetails.watchtrailer": "Ver Trailer", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL de Webhook", - "components.Settings.Notifications.NotificationsSlack.testsent": "¡Notificación de prueba enviada!", + "components.Settings.Notifications.NotificationsSlack.testsent": "¡Notificación de prueba de Slack enviada!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "¡Ajustes de notificación de Slack guardados con éxito!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Fallo al guardar ajustes de notificación de Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Para utilizar las notificaciones de Slack, deberá crear una integración de Webhook y utilizar la dirección URL de webhook proporcionada a continuación.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Configurando Notificaciones de Slack", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Habilitar Agente", "components.RequestList.RequestItem.failedretry": "Algo salió mal al reintentar la solicitud.", "components.MovieDetails.watchtrailer": "Ver Trailer", @@ -293,12 +284,9 @@ "components.Settings.Notifications.telegramsettingssaved": "¡Se han guardado los ajustes de notificación de Telegram con éxito!", "components.Settings.Notifications.telegramsettingsfailed": "La configuración de notificaciones de Telegram no se pudo guardar.", "components.Settings.Notifications.settinguptelegramDescription": "Para configurar las notificaciones de Telegram, necesitas crear un bot y obtener la clave API del bot. Además, necesitarás el ID del chat al que desea que este bot envíe notificaciones. Puede hacerlo agregando @get_id_bot al chat y enviando el comando /my_id .", - "components.Settings.Notifications.settinguptelegram": "Configuración de notificaciones de Telegram", "components.Settings.Notifications.senderName": "Nombre del remitente", - "components.Settings.Notifications.notificationtypes": "Tipos de notificación", "components.Settings.Notifications.chatId": "ID de chat", "components.Settings.Notifications.botAPI": "Token de Autenticación del Bot", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Tipos de notificación", "components.NotificationTypeSelector.mediarequested": "Contenido Solicitado", "components.NotificationTypeSelector.mediafailedDescription": "Envía una notificación cuando los medios no se agregan a los servicios (Radarr / Sonarr).", "components.NotificationTypeSelector.mediafailed": "Contenido Fallido", @@ -309,13 +297,11 @@ "i18n.request": "Solicitar", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Debes proporcionar una clave de usuario válida", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Debes proporcionar un token de aplicación válido", - "components.Settings.Notifications.NotificationsPushover.userToken": "Clave de usuario", - "components.Settings.Notifications.NotificationsPushover.testsent": "¡Notificación de prueba enviada!", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar Pushover necesitas registrar una aplicación e introducir el token API abajo (puedes utilizar uno de los nuestros iconos oficiales en Github). También necesitas tu clave de usuario.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Configuración de notificaciones Pushover", + "components.Settings.Notifications.NotificationsPushover.userToken": "Clave de usuario o grupo", + "components.Settings.Notifications.NotificationsPushover.testsent": "¡Notificación de prueba Pushover enviada!", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar Pushover necesitas registrar una aplicación e introducir el token API abajo (puedes utilizar los iconos oficiales de Overseer en Github)", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "¡Se han guardado los ajustes de notificación de Pushover!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "No se pudo guardar la configuración de notificaciones de Pushover.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Tipos de notificación", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Agente habilitado", "components.Settings.Notifications.NotificationsPushover.accessToken": "Token de aplicación/API", "components.RequestList.sortModified": "Última modificación", @@ -326,8 +312,7 @@ "components.UserList.validationpasswordminchars": "La contraseña es demasiado corta; debe tener 8 caracteres como mínimo", "components.UserList.usercreatedsuccess": "¡Usuario creado con éxito!", "components.UserList.usercreatedfailed": "Algo salió mal al intentar crear al usuario.", - "components.UserList.passwordinfodescription": "Las notificaciones por email necesitan ser habilitadas y configuradas para utilizar las contraseñas generadas automáticamente.", - "components.UserList.passwordinfo": "Información de la Contraseña", + "components.UserList.passwordinfodescription": "Habilita las notificaciones por email para poder utilizar las contraseñas generadas automáticamente.", "components.UserList.password": "Contraseña", "components.UserList.localuser": "Usuario local", "components.UserList.email": "Dirección de correo electrónico", @@ -335,17 +320,16 @@ "components.UserList.createuser": "Crear usuario", "components.UserList.createlocaluser": "Crear usuario local", "components.UserList.create": "Crear", - "components.UserList.autogeneratepassword": "Generar contraseña automáticamente", + "components.UserList.autogeneratepassword": "Generar Contraseña Automáticamente", "components.StatusBadge.status4k": "4K {status}", "components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved": "¡Configuración de notificación de webhook guardada con éxito!", "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "No se pudo guardar la configuración de notificación de webhook.", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "URL de Webhook", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "Debes proporcionar un payload de JSON válido", - "components.Settings.Notifications.NotificationsWebhook.testsent": "¡Notificación de prueba enviada!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "¡Notificación de prueba Webhook enviada!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Ayuda de variable de plantilla", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "¡Payload de JSON restablecido con éxito!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Restablecer predeterminado", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Tipos de notificación", "components.Settings.Notifications.NotificationsWebhook.customJson": "Payload de JSON", "components.Settings.Notifications.NotificationsWebhook.authheader": "Encabezado de autorización", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Habilitar Agente", @@ -400,19 +384,18 @@ "components.Discover.discover": "Descubrir", "components.Layout.UserDropdown.settings": "Ajustes", "components.Layout.UserDropdown.myprofile": "Perfil", - "components.Discover.DiscoverTvLanguage.languageSeries": "{language} Series", - "components.Discover.DiscoverTvGenre.genreSeries": "{genre} Series", - "components.Discover.DiscoverStudio.studioMovies": "{studio} Películas", - "components.Discover.DiscoverNetwork.networkSeries": "{network} Series", - "components.Discover.DiscoverMovieLanguage.languageMovies": "{language} Películas", - "components.Discover.DiscoverMovieGenre.genreMovies": "{genre} Películas", + "components.Discover.DiscoverTvLanguage.languageSeries": "Series en {language}", + "components.Discover.DiscoverTvGenre.genreSeries": "Series de {genre}", + "components.Discover.DiscoverStudio.studioMovies": "Películas de {studio}", + "components.Discover.DiscoverNetwork.networkSeries": "Series de {network}", + "components.Discover.DiscoverMovieLanguage.languageMovies": "Películas en {language}", + "components.Discover.DiscoverMovieGenre.genreMovies": "Películas de {genre}", "i18n.loading": "Cargando…", "components.ResetPassword.emailresetlink": "Enviar enlace de recuperación por email", "components.ResetPassword.email": "Dirección de Email", "components.ResetPassword.confirmpassword": "Confirmar Contraseña", "components.RequestModal.requesterror": "Algo fue mal al realizar la petición.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "No hemos podido emparejar automáticamente tu petición. Por favor, selecciona el correcto de la lista.", - "components.RequestModal.SearchByNameModal.notvdbid": "Coincidencia Manual Requerida", "components.RequestModal.SearchByNameModal.nosummary": "No se ha encontrado un resumen para este título.", "components.RequestModal.AdvancedRequester.requestas": "Pedir como", "components.RequestModal.AdvancedRequester.languageprofile": "Perfil de Idioma", @@ -471,7 +454,6 @@ "components.CollectionDetails.requestswillbecreated4k": "Los siguientes títulos tendrán peticiones en 4K:", "components.CollectionDetails.requestcollection4k": "Pedir Colección en 4K", "components.AppDataWarning.dockerVolumeMissingDescription": "El montaje del volumen {appDataPath} no se ha configurado correctamente. Todos los datos se eliminarán cuando el contenedor se pare o reinicie.", - "components.AppDataWarning.dockerVolumeMissing": "Volumen de Docker Montado no Encontrado", "components.Settings.SettingsUsers.defaultPermissions": "Permisos por Defecto", "components.Settings.SettingsJobsCache.unknownJob": "Tarea Desconocida", "components.Settings.SettingsJobsCache.sonarr-scan": "Escaneo de Sonarr", @@ -514,18 +496,15 @@ "components.Settings.Notifications.validationEmail": "Debes indicar una dirección de email válida", "components.Settings.Notifications.sendSilentlyTip": "Enviar notificaciones sin sonido", "components.Settings.Notifications.sendSilently": "Enviar silenciosamente", - "components.Settings.Notifications.emailNotificationTypesAlert": "Bandejas de Email para Notificaciones", "components.Settings.Notifications.botUsername": "Nombre de usuario del Bot", "components.Settings.Notifications.botAvatarUrl": "URL del Bot Avatar", "components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "Debes indicar una URL válida", "components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "Debes indicar una URL válida", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Debes indicar un token de acceso", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "¡Notificación de prueba enviada!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificaciones Pushbullet, necesitarás crear un token de acceso e insertarlo a continuación.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configurando Notificaciones Pushbullet", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "¡Notificación de prueba Pushbullet enviada!", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificaciones Pushbullet, necesitarás crear un token de acceso .", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "¡Los ajustes de notificación Pushbullet se han guardado con éxito!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Fallo al guardar los ajustes de la notificación Pushbullet.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Tipos de Notificación", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Habilitar Agente", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Token de Acceso", "components.Search.search": "Buscar", @@ -543,8 +522,7 @@ "components.Discover.TvGenreList.seriesgenres": "Géneros de Series", "components.Discover.MovieGenreList.moviegenres": "Géneros de Películas", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Ajustes de Notificaciones", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Habilitar Notificaciones", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID de Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID de Usuario", "components.UserProfile.UserSettings.UserGeneralSettings.user": "Usuario", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "¡Ajustes guardados con éxito!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Algo fue mal al guardar los ajustes.", @@ -600,8 +578,7 @@ "components.Settings.toastPlexConnectingFailure": "Fallo al conectar con Plex.", "components.Settings.toastPlexConnecting": "Intentando conectar con Plex…", "components.Settings.timeout": "Intervalo de Espera", - "components.Settings.settingUpPlexDescription": "Para configurar Plex, puedes introducir manualmente los detalles o seleccionar un servidor obtenido de plex.tv. Pulsa el botón de la derecha del desplegable para comprobar la conexión y obtener los servidores disponibles.", - "components.Settings.settingUpPlex": "Configurando Plex", + "components.Settings.settingUpPlexDescription": "Para configurar Plex, puedes introducir manualmente los detalles o seleccionar un servidor obtenido de plex.tv. Pulsa el botón de la derecha del desplegable para obtener los servidores disponibles.", "components.Settings.serverpresetRefreshing": "Obteniendo servidores…", "components.Settings.serverpresetPlaceholder": "Servidor de Plex", "components.Settings.serverpresetManualMessage": "Configuración manual", @@ -618,12 +595,8 @@ "components.Settings.originallanguage": "Idioma para la sección Descubrir", "components.Settings.partialRequestsEnabled": "Permitir Peticiones Parciales de Series", "components.Settings.originallanguageTip": "Filtrar contenido por idioma original", - "components.Settings.notificationsettingssaved": "¡Ajustes de notificación guardados correctamente!", - "components.Settings.notificationsettingsfailed": "Error al guardar los ajustes de notificación.", - "components.Settings.notificationAgentsSettings": "Agentes de Notificaciones", - "components.Settings.notificationAgentSettingsDescription": "Escoge los tipos de notificaciones a enviar y qué Agentes de Notificaciones a usar.", + "components.Settings.notificationAgentSettingsDescription": "Configura y habilita los agentes de notificaciones.", "components.Settings.menuUsers": "Usuarios", - "components.Settings.enablenotifications": "Habilitar notificaciones", "components.Settings.email": "Email", "components.Settings.csrfProtectionTip": "Asigna acceso a una API externa en modo solo lectura (requiere HTTPS y debe recargarse Overseer para poder aplicar los cambios)", "components.Settings.csrfProtectionHoverTip": "¡NO habilitar esta opción a menos que seas consciente de lo que estás haciendo!", @@ -648,7 +621,7 @@ "components.Settings.SettingsUsers.userSettingsDescription": "Configura los ajustes de usuarios globales y por defecto.", "components.Settings.SettingsUsers.userSettings": "Ajustes de Usuario", "components.Settings.SettingsUsers.toastSettingsSuccess": "¡Ajustes de usuario guardados con éxito!", - "components.Settings.SettingsUsers.toastSettingsFailure": "Algo fue mal mientras se guardaban llos cambios.", + "components.Settings.SettingsUsers.toastSettingsFailure": "Algo fue mal mientras se guardaban los cambios.", "components.Settings.SettingsUsers.localLogin": "Habilitar Autenticación Local", "components.Settings.SettingsLogs.time": "Marca de tiempo (timestamp)", "components.Settings.SettingsLogs.showall": "Mostrar todos los logs", @@ -663,29 +636,25 @@ "components.Settings.SettingsLogs.filterInfo": "Info", "components.Settings.SettingsLogs.filterError": "Error", "components.Settings.SettingsLogs.filterDebug": "Depuración", - "components.Settings.Notifications.pgpPrivateKeyTip": "Firmar mensajes de email encriptados (se requiere una contraseña PGP)", - "components.Settings.Notifications.pgpPrivateKey": "Clave Privada PGP", - "components.Settings.Notifications.pgpPasswordTip": "Firmar mensajes de email encriptados (se requiere una clave privada PGP)", - "components.Settings.Notifications.pgpPassword": "Contraseña de PGP", + "components.Settings.Notifications.pgpPrivateKeyTip": "Firmar mensajes de email encriptados usando OpenPGP", + "components.Settings.Notifications.pgpPrivateKey": "Clave Privada PGP", + "components.Settings.Notifications.pgpPasswordTip": "Firmar mensajes de email usando OpenPGP", + "components.Settings.Notifications.pgpPassword": "Contraseña de PGP", "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Notificaciones de email sobre Contenidos Aprobados, Contenidos Rechazados y Contenidos Disponibles se envían a todos los usuarios que hayan realizado una petición.", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "Notificaciones de email sobre Contenidos pedidos, Contenidos Aprobados Automáticamente, Contenidos Fallidos se envían a todos los usuarios con permisos de Gestionar Peticiones.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Contraseña sin asignar", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nueva Contraseña", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Contraseña Actual", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirmar Contraseña", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Debes indicar un Id de chat de Telegram válido", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Debes indicar un Id de usuario de Discord válido", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Debes indicar un Id de chat válido", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Debes indicar un Id de usuario válido", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "¡Ajustes de notificación guardardos con éxito!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Algo fue mal al guardar los cambios.", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Comienza un chat, añade el @get_id_bot, y envía el comando /my_id", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Añadir @get_id_bot al chat", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID del Chat de Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID del Chat", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Enviar notificaciones sin sonido", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar Notificaciones de Telegram silenciosas", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Encriptar mensajes email", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "Clave PúblicaPGP", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar de forma silenciosa", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notificaciones", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "El número ID de tu cuenta de Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "El número ID de tu cuenta de usuario", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filtrar contenido por disponibilidad regional", "components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filtrar contenido por idioma original", "components.UserProfile.UserSettings.UserGeneralSettings.general": "General", @@ -699,8 +668,6 @@ "components.ResetPassword.passwordreset": "Reinicio de Contraseña", "pages.errormessagewithcode": "{statusCode} - {error}", "components.UserProfile.UserSettings.unauthorizedDescription": "No tienes permiso para modificar estos ajustes de usuario.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Tu cuenta de usuario no tiene una contraseña específica para {applicationTitle}. Configura una contraseña a continuación para habilitar el uso de tu dirección de email como \"usuario local\".", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Esta cuenta de usuario no tiene una contraseña específica para {applicationTitle}. Configura una contraseña a continuación para habilitar el uso de esta cuenta como \"usuario local\"", "components.TvDetails.seasons": "{seasonCount, plural, one {# Temporada} other {# Temporadas}}", "pages.somethingwentwrong": "Algo fue mal", "pages.serviceunavailable": "Servicio No Disponible", @@ -710,7 +677,7 @@ "i18n.settings": "Ajustes", "i18n.advanced": "Avanzado", "components.UserProfile.recentrequests": "Peticiones Recientes", - "components.UserProfile.norequests": "Sin Peticiones", + "components.UserProfile.norequests": "Sin peticiones.", "components.UserProfile.UserSettings.menuPermissions": "Permisos", "components.UserProfile.UserSettings.menuNotifications": "Notificaciones", "components.UserProfile.UserSettings.menuGeneralSettings": "General", @@ -742,7 +709,6 @@ "components.PersonDetails.alsoknownas": "También Conocido como: {names}", "i18n.delimitedlist": "{a}, {b}", "i18n.view": "Ver", - "i18n.unauthorized": "Sin Autorización", "i18n.tvshow": "Series", "i18n.testing": "Probando…", "i18n.test": "Probar", @@ -774,7 +740,7 @@ "components.UserProfile.UserSettings.UserGeneralSettings.enableOverride": "Habilitar Sobreescritura", "components.TvDetails.originaltitle": "Título Original", "components.Settings.SettingsUsers.tvRequestLimitLabel": "Límite Global de Peticiones de Series", - "components.Settings.SettingsUsers.movieRequestLimitLabel": "Límte Global de Peticiones de Películas", + "components.Settings.SettingsUsers.movieRequestLimitLabel": "Límite Global de Peticiones de Películas", "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {temporada} other {temporadas}}", "components.RequestModal.QuotaDisplay.season": "temporada", "components.RequestModal.QuotaDisplay.requiredquotaUser": "Este usuario necesita tener al menos {seasons} {seasons, plural, one {petición de temporada} other {peticiones de temporadas}} restante(s) para poder enviar una petición para esta serie.", @@ -787,10 +753,67 @@ "components.RequestModal.QuotaDisplay.movie": "película", "components.RequestModal.QuotaDisplay.allowedRequestsUser": "Este usuario tiene permitido {limit} {type} cada {days} días.", "components.RequestModal.QuotaDisplay.allowedRequests": "Se te permite pedir {limit} {type} cada {days} días.", - "components.QuotaSelector.unlimited": "Ilimitada", + "components.QuotaSelector.unlimited": "Ilimitadas", "components.QuotaSelector.tvRequestLimit": "{quotaLimit} temporada(s) por {quotaDays} día(s)", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} película(s) por {quotaDays} día(s)", "components.MovieDetails.originaltitle": "Título Original", "components.LanguageSelector.originalLanguageDefault": "Todos los Idiomas", - "components.LanguageSelector.languageServerDefault": "({language}) por defecto" + "components.LanguageSelector.languageServerDefault": "({Language}) por defecto", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {cambio} other {cambios}} por detrás", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Tu cuenta no tiene configurada una contraseña actualmente. Configure una contraseña a continuación para habilitar el acceso como \"usuario local\" utilizando tu dirección de email.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Esta cuenta de usuario no tiene configurada una contraseña actualmente. Configure una contraseña a continuación para habilitar el acceso como \"usuario local\"", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Debes introducir una clave pública PGP valida", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "¡Ajustes de notificaciones de Telegram guardados correctamente!", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Error al guardar los ajustes de notificaciones de Telegram.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Encriptar mensajes por email usando OpenPGP2", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Clave Pública PGP", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Habilitar Notificaciones", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Habilitar Notificaciones", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Habilitar Menciones", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "¡Ajustes de notificación por email guardados correctamente!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Error al guardar los ajustes de notificaciones por email.", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "Email", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "¡Los ajustes de notificaciones de Discord se han guardado correctamente!", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "No se han podido guardar los ajustes de notificaciones de Discord.", + "components.Settings.serviceSettingsDescription": "Configura tu(s) servidor(es) {serverType} a continuación. Puedes conectar a múltiples servidores de {serverType}, pero solo dos de ellos pueden ser marcados como por defecto (uno no-4k y otro 4k). Los administrador podrán modificar el servidor usado al procesar nuevas peticiones antes de su aprobación.", + "components.Settings.mediaTypeMovie": "película", + "components.Settings.SonarrModal.testFirstTags": "Probar conexión para cargar etiquetas", + "components.Settings.SonarrModal.tags": "Etiquetas", + "components.Settings.SonarrModal.selecttags": "Seleccionar etiquetas", + "components.Settings.SonarrModal.notagoptions": "Sin etiquetas.", + "components.Settings.SonarrModal.loadingTags": "Cargando etiquetas…", + "components.Settings.SonarrModal.edit4ksonarr": "Modificar servidor 4K Sonarr", + "components.Settings.SonarrModal.default4kserver": "Servidor 4K por defecto", + "components.Settings.SonarrModal.create4ksonarr": "Añadir nuevo servidor Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Etiquetas Anime", + "components.Settings.noDefaultServer": "Al menos un servidor {serverType} debe marcarse como por defecto para que las peticiones de {mediaType} sean procesadas.", + "components.Settings.noDefaultNon4kServer": "Si solo tienes un único servidor {serverType} para contenidos 4K y no 4K (o si solo descargas contenidos 4k), tu servidor {serverType} NO debería marcarse como un servidor 4k.", + "components.Settings.mediaTypeSeries": "series", + "components.Settings.SettingsAbout.uptodate": "Actualizado", + "components.Settings.SettingsAbout.outofdate": "Desactualizado", + "components.Settings.RadarrModal.testFirstTags": "Probar conexión para cargar etiquetas", + "components.Settings.RadarrModal.tags": "Etiquetas", + "components.Settings.RadarrModal.selecttags": "Seleccionar etiquetas", + "components.Settings.RadarrModal.notagoptions": "Sin etiquetas.", + "components.Settings.RadarrModal.loadingTags": "Cargando etiquetas…", + "components.Settings.RadarrModal.edit4kradarr": "Modificar servidor Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Servidor 4K por defecto", + "components.Settings.RadarrModal.create4kradarr": "Añadir un nuevo servidor Radarr 4K", + "components.Settings.Notifications.validationPgpPrivateKey": "Debes indicar una clave privada PGP si se ha introducido una contraseña PGP", + "components.Settings.Notifications.validationPgpPassword": "Debes indicar una contraseña PGP si se ha introducido una clave privada PGP", + "components.Settings.Notifications.botUsernameTip": "Permite a los usuarios iniciar un chat con el bot y configurar sus propias notificaciones", + "components.RequestModal.pendingapproval": "Tu petición está pendiente de aprobación.", + "components.RequestModal.AdvancedRequester.tags": "Etiquetas", + "components.RequestModal.AdvancedRequester.selecttags": "Seleccionar etiquetas", + "components.RequestModal.AdvancedRequester.notagoptions": "Sin etiquetas.", + "components.RequestList.RequestItem.mediaerror": "El título asociado a esta petición ya no está disponible.", + "components.RequestList.RequestItem.deleterequest": "Borrar Petición", + "components.RequestList.RequestItem.cancelRequest": "Cancelar Petición", + "components.RequestCard.mediaerror": "El título asociado a esta petición ya no está disponible.", + "components.RequestCard.deleterequest": "Borrar Petición", + "components.NotificationTypeSelector.notificationTypes": "Tipos de Notificación", + "components.Layout.VersionStatus.streamstable": "Overseer (Estable)", + "components.Layout.VersionStatus.streamdevelop": "Overseer (Desarrollo)", + "components.Layout.VersionStatus.outofdate": "Desactualizado", + "components.Discover.noRequests": "Sin peticiones." } diff --git a/src/i18n/locale/fr.json b/src/i18n/locale/fr.json index d955d485..269983e3 100644 --- a/src/i18n/locale/fr.json +++ b/src/i18n/locale/fr.json @@ -1,27 +1,25 @@ { "components.Discover.discovermovies": "Films populaires", "components.Discover.discovertv": "Séries populaires", - "components.Discover.nopending": "Aucune demande en attente", "components.Discover.popularmovies": "Films populaires", "components.Discover.populartv": "Séries populaires", "components.Discover.recentlyAdded": "Ajouts récents", - "components.Discover.recentrequests": "Demandes d'ajouts récentes", + "components.Discover.recentrequests": "Demandes récentes", "components.Discover.trending": "Tendances", "components.Discover.upcoming": "Prochaines sorties", "components.Discover.upcomingmovies": "Prochaines sorties", "components.Layout.LanguagePicker.changelanguage": "Changer la langue", "components.Layout.SearchInput.searchPlaceholder": "Rechercher des films et des séries", "components.Layout.Sidebar.dashboard": "Découvrir", - "components.Layout.Sidebar.requests": "Demandes d'ajout", + "components.Layout.Sidebar.requests": "Demandes", "components.Layout.Sidebar.settings": "Paramètres", "components.Layout.Sidebar.users": "Utilisateurs", "components.Layout.UserDropdown.signout": "Se déconnecter", - "components.Layout.alphawarning": "Ce logiciel est en version ALPHA. Certaines fonctionnalités risquent de ne pas fonctionner ou d'être instable. Veuillez signaler tout problème sur notre GitHub !", "components.MovieDetails.budget": "Budget", "components.MovieDetails.cast": "Casting", "components.MovieDetails.manageModalClearMedia": "Effacer toutes les données médias", "components.MovieDetails.manageModalClearMediaWarning": "* Cette action effacera toutes les données sur ce film de manière irréversible, y compris les demandes. Si cet élément existe dans votre bibliothèque Plex, les informations du média seront recréées au prochain scan.", - "components.MovieDetails.manageModalNoRequests": "Aucune demande", + "components.MovieDetails.manageModalNoRequests": "Aucune demande.", "components.MovieDetails.manageModalRequests": "Demandes d'ajout", "components.MovieDetails.manageModalTitle": "Gérer le film", "components.MovieDetails.originallanguage": "Langue originale", @@ -37,17 +35,17 @@ "components.RequestBlock.seasons": "{seasonCount, plural, one {Saison} other {Saisons}}", "components.RequestCard.seasons": "{seasonCount, plural, one {Saison} other {Saisons}}", "components.RequestList.RequestItem.seasons": "{seasonCount, plural, one {Saison} other {Saisons}}", - "components.RequestList.requests": "Demandes d'ajout", + "components.RequestList.requests": "Demandes", "components.RequestModal.cancel": "Annuler la demande", "components.RequestModal.extras": "Extras", "components.RequestModal.numberofepisodes": "Nbr d'épisodes", "components.RequestModal.pendingrequest": "Demande en attente pour {title}", "components.RequestModal.requestCancel": "Demande pour {title} annulée.", "components.RequestModal.requestSuccess": "{title} demandé avec succès !", - "components.RequestModal.requestadmin": "Votre demande d'ajout va être validée immédiatement.", - "components.RequestModal.requestfrom": "Une demande d'ajout de {username} est en attente.", + "components.RequestModal.requestadmin": "Cette demande sera validée automatiquement.", + "components.RequestModal.requestfrom": "Une demande de {username} est en attente.", "components.RequestModal.requestseasons": "Demander {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}", - "components.RequestModal.requesttitle": "Demander l'ajout de {title}", + "components.RequestModal.requesttitle": "Demander {title}", "components.RequestModal.season": "Saison", "components.RequestModal.seasonnumber": "Saison {number}", "components.RequestModal.selectseason": "Selectionner Saison(s)", @@ -59,7 +57,7 @@ "components.Settings.Notifications.enableSsl": "Activer SSL", "components.Settings.Notifications.smtpHost": "Hôte SMTP", "components.Settings.Notifications.smtpPort": "Port SMTP", - "components.Settings.Notifications.validationSmtpHostRequired": "Vous devez fournir un nom d'hôte ou une adresse IP", + "components.Settings.Notifications.validationSmtpHostRequired": "Vous devez fournir un nom d'hôte ou une adresse IP valide", "components.Settings.Notifications.validationSmtpPortRequired": "Vous devez fournir un numéro de port valide", "components.Settings.Notifications.webhookUrl": "URL de webhook", "components.Settings.Notifications.webhookUrlPlaceholder": "Paramètres du serveur → Intégrations → Webhooks", @@ -140,18 +138,15 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "Services", "components.Settings.notificationsettings": "Paramètres de notification", - "components.Settings.notificationsettingsDescription": "Configurer les paramètres de notification généraux. Les paramètres ci-dessous s'appliquent à tous les agents de notification.", "components.Settings.notrunning": "Pas en exécution", "components.Settings.plexlibraries": "Bibliothèques Plex", "components.Settings.plexlibrariesDescription": "Les bibliothèques Overseerr recherchent les titres. Configurez et sauvegardez vos paramètres de connexion Plex, puis cliquez sur le bouton ci-dessous si aucune bibliothèque n'est répertoriée.", "components.Settings.plexsettings": "Paramètres Plex", "components.Settings.plexsettingsDescription": "Configurer les paramètres de votre serveur Plex. Overseerr utilise votre serveur Plex pour scanner votre bibliothèque par intervalles et voir quels contenus sont disponibles.", "components.Settings.port": "Port", - "components.Settings.radarrSettingsDescription": "Configurez votre connexion Radarr ci-dessous. Vous pouvez avoir plusieurs configurations Radarr, mais seulement deux peuvent être actives par défaut à tout moment (une pour la HD standard et une pour la 4K). Les administrateurs peuvent remplacer le serveur qui est utilisé pour les nouvelles demandes.", "components.Settings.radarrsettings": "Paramètres Radarr", "components.Settings.servername": "Nom du serveur", "components.Settings.servernamePlaceholder": "Nom de serveur Plex", - "components.Settings.sonarrSettingsDescription": "Configurez votre connexion Sonarr ci-dessous. Vous pouvez avoir plusieurs configurations Sonarr, mais seulement deux peuvent être actives par défaut à tout moment (une pour la HD standard et une pour la 4K). Les administrateurs peuvent remplacer le serveur qui est utilisé pour les nouvelles demandes.", "components.Settings.sonarrsettings": "Paramètres Sonarr", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Commencer le scan", @@ -166,8 +161,8 @@ "components.TvDetails.cast": "Casting", "components.TvDetails.manageModalClearMedia": "Effacer toutes les données média", "components.TvDetails.manageModalClearMediaWarning": "* Cette action supprimera irrémédiablement toutes les données pour cette série, y compris toutes les demandes. Si cet élément existe dans votre bibliothèque Plex, les informations du média seront recréées lors du prochain scan.", - "components.TvDetails.manageModalNoRequests": "Aucune demande", - "components.TvDetails.manageModalRequests": "Demandes d'ajout", + "components.TvDetails.manageModalNoRequests": "Aucune demande.", + "components.TvDetails.manageModalRequests": "Demandes", "components.TvDetails.manageModalTitle": "Gérer les séries", "components.TvDetails.originallanguage": "Langue originale", "components.TvDetails.overview": "Résumé", @@ -179,7 +174,7 @@ "components.UserList.lastupdated": "Denière mise à jour", "components.UserList.plexuser": "Utilisateur Plex", "components.UserList.role": "Rôle", - "components.UserList.totalrequests": "Demandes d'ajout totales", + "components.UserList.totalrequests": "Total des demandes", "components.UserList.user": "Utilisateur", "components.UserList.userlist": "Liste des utilisateurs", "i18n.approve": "Valider", @@ -218,9 +213,7 @@ "components.UserList.userdeleteerror": "Une erreur s'est produite lors de la suppression de l'utilisateur.", "components.UserList.userdeleted": "Utilisateur supprimé avec succès !", "components.UserList.deleteuser": "Supprimer l'utilisateur", - "components.UserList.deleteconfirm": "Voulez-vous vraiment supprimer cet utilisateur ? Toutes les données de demande existantes de cet utilisateur seront supprimées.", - "components.Settings.nodefaultdescription": "Au moins un serveur doit être marqué par défaut avant que toute demande parvienne à vos services.", - "components.Settings.nodefault": "Aucun serveur par défaut", + "components.UserList.deleteconfirm": "Voulez-vous vraiment supprimer cet utilisateur ? Toutes les données de demande de cet utilisateur seront supprimées de façon permanente.", "components.Settings.SonarrModal.testFirstRootFolders": "Testez la connexion pour charger les dossiers racine", "components.Settings.SonarrModal.testFirstQualityProfiles": "Testez la connexion pour charger les profils qualité", "components.Settings.SonarrModal.loadingrootfolders": "Chargement des dossiers racine…", @@ -248,12 +241,11 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Voir le journal des modifications", "components.Settings.SettingsAbout.Releases.versionChangelog": "Journal des modifications de version", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "Les dernières modifications apportées à la branche develop d'Overseerr ne sont pas affichées ci-dessous. Veuillez consulter l'historique des validations de cette branche sur GitHub pour plus de détails.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Version de développement", "components.Settings.SettingsAbout.Releases.releases": "Versions", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Données de sortie indisponibles. GitHub est-il en panne ?", "components.Settings.SettingsAbout.Releases.latestversion": "Dernière version", "components.Settings.SettingsAbout.Releases.currentversion": "Version actuelle", - "components.Settings.Notifications.testsent": "Notification de test envoyée !", + "components.Settings.Notifications.testsent": "Notification de test Telegram envoyée !", "components.UserList.importfromplexerror": "Une erreur s'est produite durant l'importation d'utilisateurs depuis Plex.", "components.UserList.importfromplex": "Importer des utilisateurs depuis Plex", "components.UserList.importedfromplex": "{userCount, plural, one {# nouvel utilisateur} other {# nouveaux utilisateurs}} importé(s) depuis Plex avec succès !", @@ -268,7 +260,7 @@ "components.TvDetails.watchtrailer": "Regarder la bande-annonce", "components.MovieDetails.watchtrailer": "Regarder la bande-annonce", "components.CollectionDetails.requestswillbecreated": "Des demandes seront créées pour les titres suivants :", - "components.CollectionDetails.requestcollection": "Demander une collection", + "components.CollectionDetails.requestcollection": "Demander la collection", "components.CollectionDetails.requestSuccess": "{title} demandé avec succès !", "components.CollectionDetails.overview": "Résumé", "components.CollectionDetails.numberofmovies": "{count} films", @@ -276,13 +268,12 @@ "i18n.retry": "Réessayer", "i18n.failed": "Échec", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL webhook", - "components.Settings.Notifications.NotificationsSlack.testsent": "Notification de test envoyée !", + "components.Settings.Notifications.NotificationsSlack.testsent": "Notification de test Slack envoyée !", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Les paramètres de notifications Slack ont été enregistrés avec succès !", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Impossible d'enregistrer les paramètres des notifications Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Pour configurer les notifications Slack, vous aurez besoin de créer une intégration de Webhook Entrant et d'ajouter l'URL fournie du Webhook ci-dessous.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Paramétrage des notifications Slack", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Activer l'agent", - "components.RequestList.RequestItem.failedretry": "Une erreur s'est produite lors du renvoi de la demande d'ajout.", + "components.RequestList.RequestItem.failedretry": "Une erreur s'est produite lors du renvoi de la demande.", "components.Settings.Notifications.validationChatIdRequired": "Vous devez fournir un identifiant de discussion valide", "components.Settings.Notifications.botAPI": "Jeton d'authentification du bot", "components.Settings.Notifications.validationBotAPIRequired": "Vous devez fournir la clé d'authentification du bot", @@ -291,13 +282,10 @@ "components.Settings.Notifications.senderName": "Nom de l'expéditeur", "components.Settings.Notifications.chatId": "ID discussion", "components.Settings.Notifications.settinguptelegramDescription": "Pour configurer les notifications Telegram, vous aurez besoin de créer un bot et obtenir la clé API du bot. De plus, vous aurez besoin de l'identifiant de conversion pour la conversation à laquelle vous souhaitez envoyer des notifications. Vous pouvez le trouver en ajoutant @get_id_bot à la conversation -de groupe- et en exécutant la commande /my_id.", - "components.Settings.Notifications.settinguptelegram": "Configuration des notifications Telegram", "components.StatusChacker.reloadOverseerr": "Recharger", "components.StatusChacker.newversionavailable": "Mise à jour de l'application", "components.StatusChacker.newversionDescription": "Overseerr a été mis à jour ! Veuillez cliquer sur le bouton ci-dessous pour recharger la page.", "components.Settings.SettingsAbout.documentation": "Documentation", - "components.Settings.Notifications.notificationtypes": "Types de notification", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Types de notification", "components.NotificationTypeSelector.mediarequestedDescription": "Envoie une notification quand un média est demandé et nécessite une validation.", "components.NotificationTypeSelector.mediarequested": "Média demandé", "components.NotificationTypeSelector.mediafailedDescription": "Envoie une notification lorsqu'un média demandé n'a pas pu être ajouté sur Radarr /Sonarr.", @@ -309,13 +297,11 @@ "i18n.request": "Demander", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Vous devez fournir un jeton utilisateur valide", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Vous devez fournir un jeton d'application valide", - "components.Settings.Notifications.NotificationsPushover.userToken": "Clé d'utilisateur", - "components.Settings.Notifications.NotificationsPushover.testsent": "Notification de test envoyée !", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Pour configurer Pushover, vous aurez besoin d'enregistrer une application et d'ajouter le jeton API ci-dessous. Vous pouvez utiliser l'une des icônes présentes dans le dossier public sur GitHub. Vous aurez également besoin du jeton d'utilisateur.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Configuration des notifications Pushover", + "components.Settings.Notifications.NotificationsPushover.userToken": "Clé d'utilisateur ou de groupe", + "components.Settings.Notifications.NotificationsPushover.testsent": "Notification Pushover de test envoyée !", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Pour configurer Pushover, vous aurez besoin d'enregistrer une application et d'ajouter le jeton API ci-dessous. (Vous pouvez utiliser l'une des icônes présentes dans le dossier public sur GitHub.)", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Paramètres de notification pushover enregistrés avec succès !", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Les paramètres de notification pushover n'ont pas pu être enregistrés.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Types de notification", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Activer l'agent", "components.Settings.Notifications.NotificationsPushover.accessToken": "Clé d'API /d'application", "components.RequestList.sortModified": "Dernière modification", @@ -325,9 +311,8 @@ "components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved": "Paramètres de notification Webhook enregistrés avec succès !", "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Échec de l'enregistrement des paramètres de notification du webhook.", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "URL webhook", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Notification de test envoyée !", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Notification Webhook de test envoyée !", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Aide sur les variables de modèle", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Types de notification", "components.Settings.Notifications.NotificationsWebhook.authheader": "En-tête d'autorisation", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Activer l'agent", "components.RequestModal.request4ktitle": "Demander {title} en 4K", @@ -352,7 +337,6 @@ "components.UserList.validationpasswordminchars": "Le mot de passe est trop court ; il doit contenir au moins 8 caractères", "components.UserList.usercreatedsuccess": "L'utilisateur a bien été créé !", "components.UserList.usercreatedfailed": "Une erreur s'est produite lors de la création de l'utilisateur.", - "components.UserList.passwordinfo": "Informations sur le mot de passe", "components.UserList.password": "Mot de passe", "components.UserList.localuser": "Utilisateur local", "components.UserList.creating": "Création…", @@ -360,7 +344,7 @@ "components.UserList.createlocaluser": "Créer un utilisateur local", "components.UserList.create": "Créer", "components.UserList.autogeneratepassword": "Générer automatiquement le mot de passe", - "components.UserList.passwordinfodescription": "Les notifications par e-mail doivent être configurées et activées afin de pouvoir utiliser les mots de passe générés automatiquement.", + "components.UserList.passwordinfodescription": "Activez les notifications par e-mail pour permettre la génération automatique de mots de passe.", "components.UserList.email": "Adresse e-mail", "components.Login.validationpasswordrequired": "Vous devez fournir un mot de passe", "components.Login.validationemailrequired": "Vous devez fournir un e-mail valide", @@ -370,8 +354,8 @@ "components.Login.email": "Adresse e-mail", "components.MediaSlider.ShowMoreCard.seemore": "Voir plus", "i18n.edit": "Modifier", - "components.RequestModal.requestedited": "Demande modifiée.", - "components.RequestModal.requestcancelled": "Demande annulée.", + "components.RequestModal.requestedited": "Demande pour {title} modifiée avec succès !", + "components.RequestModal.requestcancelled": "Demande pour {title} annulée.", "components.RequestModal.errorediting": "Une erreur s'est produite lors de la modification de la demande.", "components.RequestModal.autoapproval": "Validation automatique", "components.RequestModal.AdvancedRequester.rootfolder": "Dossier Racine", @@ -388,19 +372,14 @@ "components.NotificationTypeSelector.mediadeclinedDescription": "Envoie une notification lorsqu'un média demandé est refusé.", "i18n.experimental": "Expérimentale", "components.Settings.hideAvailable": "Masquer les médias disponibles", - "components.RequestModal.requesterror": "Il y a eu un problème lors de la demande d'ajout.", - "components.RequestModal.SearchByNameModal.notvdbiddescription": "Nous n'avons pas pu associer votre demande d'ajout automatiquement. Veuillez sélectionner l'association correcte dans la liste ci-dessous.", - "components.RequestModal.SearchByNameModal.notvdbid": "Association manuelle requise", + "components.RequestModal.requesterror": "Il y a eu un problème lors de la demande.", + "components.RequestModal.SearchByNameModal.notvdbiddescription": "Nous n'avons pas pu associer votre demande automatiquement. Veuillez sélectionner l'association correcte dans la liste ci-dessous.", "components.RequestModal.SearchByNameModal.nosummary": "Aucun résumé trouvé pour ce titre.", "components.Login.signinwithplex": "Utilisez votre compte Plex", "components.Login.signin": "Connexion", "components.Login.signinheader": "Connectez-vous pour continuer", "components.Login.signingin": "Connexion en cours…", - "components.Settings.notificationsettingssaved": "Paramètres de notification enregistrés avec succès !", - "components.Settings.notificationsettingsfailed": "Les paramètres de notification n'ont pas pu être enregistrés.", - "components.Settings.notificationAgentsSettings": "Agents de notification", - "components.Settings.notificationAgentSettingsDescription": "Choisissez le ou les types de notifications à envoyer, et quel agent de notification utiliser.", - "components.Settings.enablenotifications": "Activer les Notifications", + "components.Settings.notificationAgentSettingsDescription": "Configurer et activer les agents de notification.", "components.PlexLoginButton.signinwithplex": "Connectez-vous", "components.PlexLoginButton.signingin": "Connexion en cours…", "components.UserList.userssaved": "Les permissions d'utilisateur ont été enregistrées avec succès !", @@ -440,8 +419,7 @@ "components.Settings.toastPlexConnectingFailure": "Échec de connexion à Plex.", "components.Settings.toastPlexConnecting": "Tentative de connexion à Plex…", "components.Settings.timeout": "Délai d'expiration", - "components.Settings.settingUpPlexDescription": "Pour configurer Plex, vous pouvez soit entrer vos coordonnées manuellement ou choisir parmi l'un des serveurs disponibles récupérés sur plex.tv. Appuyez sur le bouton à droite de la liste déroulante pour actualiser la liste pour tester la connectivité et récupérer les serveurs disponibles.", - "components.Settings.settingUpPlex": "Configuration de Plex", + "components.Settings.settingUpPlexDescription": "Pour configurer Plex, vous pouvez soit entrer vos coordonnées manuellement ou choisir parmi l'un des serveurs disponibles récupérés sur plex.tv. Appuyez sur le bouton à droite de la liste déroulante pour actualiser la liste des serveurs disponibles.", "components.Settings.serverpresetRefreshing": "Récupération des serveurs…", "components.Settings.serverpresetPlaceholder": "Serveur Plex", "components.Settings.serverpresetManualMessage": "Configuration manuelle", @@ -559,14 +537,11 @@ "components.PermissionEdit.autoapprove4kDescription": "Accorder la validation automatique pour toutes les demandes 4K faites par cet utilisateur.", "components.PermissionEdit.autoapprove4k": "Validation automatique 4K", "components.AppDataWarning.dockerVolumeMissingDescription": "Le montage du volume {appDataPath} n'a pas été configuré correctement. Toutes les données seront effacées lorsque le conteneur est arrêté ou redémarré.", - "components.AppDataWarning.dockerVolumeMissing": "Monture de volume Docker manquante", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Identifiant Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Identifiant", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Paramètres de notification", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Aucun mot de passe défini", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nouveau mot de passe", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Mot de passe actuel", "components.UserProfile.UserSettings.UserPasswordChange.password": "Mot de passe", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Ce compte utilisateur n'a pas de mot de passe spécifique à {applicationTitle}, pour le moment. Configurez un mot de passe ci-dessous, pour permettre à ce compte de se connecter en tant qu'utilisateur local.", "components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Paramètres enregistrés avec succès !", "components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "Une erreur s'est produite lors de l'enregistrement des paramètres.", "components.UserProfile.recentrequests": "Demandes récentes", @@ -575,16 +550,14 @@ "components.UserProfile.UserSettings.menuGeneralSettings": "Général", "components.UserProfile.UserSettings.menuChangePass": "Mot de passe", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Vous devez fournir un jeton d'accès", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notification de test envoyée !", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configurer les notifications pushbullet", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notification Pushbullet de test envoyée !", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Les paramètres de notification Pushbullet n'ont pas pu être enregistrés.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Types de notification", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Activer l'agent", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Jeton d'accès", "components.Layout.UserDropdown.settings": "Paramètres", "components.Layout.UserDropdown.myprofile": "Profil", "components.CollectionDetails.requestcollection4k": "Demander la collection en 4K", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Pour configurer les notifications Pushbullet, vous aurez besoin de créer un token d'accès et de l'ajouter ci-dessous.", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Pour configurer les notifications Pushbullet, vous aurez besoin de créer un token d'accès.", "components.UserProfile.UserSettings.UserPermissions.permissions": "Permissions", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "Le mot de passe est trop court, il doit contenir un minimum de 8 caractères", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "Vous devez fournir un nouveau mot de passe", @@ -593,11 +566,10 @@ "components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "Vous devez confirmer le nouveau mot de passe", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Mot de passe enregistré avec succès !", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Un problème est survenu lors de l'enregistrement du mot de passe.", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "L'ID de votre compte utilisateur (Discord) doit être valide", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Vous devez fournir un identifiant valide", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Paramètres de notification enregistrés avec succès !", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Un problème est survenu pendant l'enregistrement des paramètres.", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Activer les notifications", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "L''ID de votre compte Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "L''ID de votre compte utilisateur", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Les paramètres ont été enregistrés avec succès !", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Un problème est survenu pendant l'enregistrement des paramètres.", "components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Utilisateur Plex", @@ -622,7 +594,6 @@ "components.Settings.originallanguage": "Langue à découvrir", "components.RegionSelector.regionDefault": "Toutes les régions", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "Les notifications par e-mail « Média demandé », « Média validé automatiquement » et « Échec d’ajout du média » sont envoyées à tous les utilisateurs bénéficiant de la permission « Gérer les demandes ».", - "components.Settings.Notifications.emailNotificationTypesAlert": "Destinataires des notifications par e-mail", "components.Settings.webhook": "Webhook", "components.Settings.email": "E-mail", "components.RegionSelector.regionServerDefault": "Défaut ({region})", @@ -645,10 +616,9 @@ "components.TvDetails.seasons": "{seasonCount, plural, one {# Saison} other {# Saisons}}", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Envoyer des notifications sans son", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Démarre une discussion, ajoute @get_id_bot, et utilise la commande /my_id", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Ajoute @get_id_bot à la discussion", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID de discussion Telegram", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Envoie les messages Telegram silencieusement", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Vous devez fournir un identifiant de discussion Telegram valide", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID de discussion", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Envoie les messages silencieusement", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Vous devez fournir un identifiant de chat valide", "components.Settings.Notifications.botUsername": "Pseudonyme du Bot", "components.Discover.NetworkSlider.networks": "Diffuseurs", "components.RequestList.RequestItem.modified": "Modifiée", @@ -668,8 +638,8 @@ "components.Settings.Notifications.botAvatarUrl": "L'URL de l'avatar de votre Bot", "components.Settings.SettingsUsers.userSettingsDescription": "Configurer les paramètres généraux et par défaut de l'utilisateur.", "components.Settings.SettingsUsers.toastSettingsFailure": "Un problème est survenu pendant la sauvegarde des paramètres.", - "components.Settings.SettingsUsers.localLogin": "Activer la connexion des utilisateurs locaux", - "components.Settings.SettingsUsers.defaultPermissions": "Permissions par défaut de l'utilisateur", + "components.Settings.SettingsUsers.localLogin": "Activer la connexion locale", + "components.Settings.SettingsUsers.defaultPermissions": "Permissions par défaut", "components.UserProfile.ProfileHeader.userid": "ID utilisateur : {userid}", "components.UserProfile.ProfileHeader.joindate": "Membre depuis le {joindate}", "components.Settings.menuUsers": "Utilisateurs", @@ -680,15 +650,13 @@ "components.NotificationTypeSelector.mediaAutoApprovedDescription": "Envoie une notification quand la demande d'un média est validé automatiquement.", "components.UserProfile.UserSettings.unauthorizedDescription": "Vous n'avez pas l'autorisation de modifier les paramètres de cet utilisateur.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "Vous ne pouvez pas modifier vos propres permissions.", - "components.Settings.Notifications.pgpPrivateKeyTip": "Signer des e-mails chiffrés (le mot de passe PGP est également requis)", - "components.Settings.Notifications.pgpPasswordTip": "Signer des e-mails chiffrés (la clé privée PGP est également requise)", - "components.UserProfile.norequests": "Aucune demandes", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Chiffrer les e-mails", - "components.Settings.Notifications.pgpPrivateKey": "PGP Clé privée", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP Clé publique", + "components.Settings.Notifications.pgpPrivateKeyTip": "Signer des emails chiffrés en utilisant OpenPGP", + "components.Settings.Notifications.pgpPasswordTip": "Signer des emails chiffrés en utilisant OpenPGP", + "components.UserProfile.norequests": "Aucune demande.", + "components.Settings.Notifications.pgpPrivateKey": "PGP Clé privée", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minutes", "components.TvDetails.episodeRuntime": "Durée d'un épisode", - "components.Settings.Notifications.pgpPassword": "PGP mot de passe", + "components.Settings.Notifications.pgpPassword": "PGP mot de passe", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.Settings.partialRequestsEnabled": "Permettre les demandes partielles des séries", "components.RequestModal.requestall": "Demander toutes les saisons", @@ -725,7 +693,6 @@ "components.ResetPassword.passwordreset": "Réinitialiser le mot de passe", "pages.internalservererror": "Erreur interne du serveur", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Un problème est survenu lors de l'enregistrement du mot de passe. Votre mot de passe actuel a-t-il été saisi correctement ?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Votre compte n'a actuellement pas de mot de passe spécifiquement pour {applicationTitle}. Configurez un mot de passe ci-dessous pour activer la connexion en tant qu'« utilisateur local » à l'aide de votre adresse e-mail.", "components.Settings.cacheImagesTip": "Optimiser et stocker toutes les images localement (consomme une quantité considérable d'espace disque)", "components.Settings.cacheImages": "Activer la mise en cache d'image", "components.Settings.SettingsLogs.time": "Horodatage", @@ -756,5 +723,97 @@ "components.QuotaSelector.movieRequestLimit": "{quotaLimit} film(s) par {quotaDays} jour(s)", "components.TvDetails.originaltitle": "Titre original", "components.MovieDetails.originaltitle": "Titre original", - "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {saison} other {saisons}}" + "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {saison} other {saisons}}", + "components.LanguageSelector.originalLanguageDefault": "Toutes les langues", + "components.LanguageSelector.languageServerDefault": "({language}) par défaut", + "i18n.tvshow": "Séries", + "i18n.test": "Tester", + "i18n.save": "Sauvegarder les changements", + "i18n.request4k": "Demande 4K", + "i18n.movie": "Film", + "components.UserProfile.totalrequests": "Total des demandes", + "components.UserProfile.requestsperdays": "{limit} restantes", + "components.UserProfile.limit": "{remaining} sur {limit}", + "i18n.view": "Voir", + "i18n.testing": "Test en cours…", + "i18n.status": "Statut", + "i18n.saving": "Sauvegarde en cours…", + "i18n.resultsperpage": "Afficher {pageSize} résultats par page", + "i18n.requesting": "Demande en cours…", + "i18n.previous": "Précédent", + "i18n.notrequested": "Non demandé", + "i18n.noresults": "Aucun résultat.", + "i18n.next": "Suivant", + "i18n.canceling": "Annulation…", + "i18n.back": "Retour", + "i18n.areyousure": "Êtes-vous sûr?", + "i18n.all": "Todas", + "components.UserProfile.seriesrequest": "Demandes de séries", + "components.UserProfile.pastdays": "{type} (derniers {days} jours)", + "components.UserProfile.movierequests": "Demandes de films", + "components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit": "Limite de demandes de films", + "components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit": "Limite de demandes de séries", + "components.UserProfile.UserSettings.UserGeneralSettings.enableOverride": "Activer le contournement", + "components.Settings.SonarrModal.loadingTags": "Chargement des tags en cours…", + "components.Settings.SonarrModal.edit4ksonarr": "Modifier le serveur Sonarr 4K", + "components.Settings.SonarrModal.default4kserver": "Serveur 4K par défaut", + "components.Settings.SonarrModal.create4ksonarr": "Ajouter un nouveau serveur Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Tags d'animés", + "components.Settings.SettingsUsers.tvRequestLimitLabel": "Limite globale de demandes de séries", + "components.Settings.SettingsUsers.movieRequestLimitLabel": "Limite globale de demandes de films", + "components.Settings.SonarrModal.testFirstTags": "Tester la connexion pour charger les tags", + "components.Settings.RadarrModal.testFirstTags": "Tester la connexion pour charger les tags", + "components.Settings.SonarrModal.tags": "Tags", + "components.Settings.RadarrModal.tags": "Tags", + "components.Settings.SonarrModal.selecttags": "Sélectionner les tags", + "components.Settings.RadarrModal.selecttags": "Sélectionner les tags", + "components.Settings.SonarrModal.notagoptions": "Aucun tag.", + "components.Settings.RadarrModal.notagoptions": "Aucun tag.", + "components.Settings.RadarrModal.loadingTags": "Chargement des tags en cours…", + "components.Settings.RadarrModal.edit4kradarr": "Modifier le serveur Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Serveur 4K par défaut", + "components.Settings.RadarrModal.create4kradarr": "Ajouter un nouveau serveur Radarr 4K", + "components.RequestModal.AdvancedRequester.tags": "Tags", + "components.RequestModal.AdvancedRequester.selecttags": "Sélectionner les tags", + "components.RequestModal.AdvancedRequester.notagoptions": "Aucun tag.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Chiffrer les emails en utilisant OpenPGP", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Votre compte n’a actuellement pas de mot de passe. Configurez un mot de passe ci-dessous pour activer la connexion en tant qu’ \"utilisateur local\" en utilisant votre adresse e-mail.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Ce compte utilisateur n’a actuellement pas de mot de passe. Configurez un mot de passe ci-dessous pour permettre à ce compte de se connecter en tant \"qu’utilisateur local.\"", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Vous devez fournir une clé publique PGP valide", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Paramètres de notification Telegram enregistrés avec succès !", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Impossible d’enregistrer les paramètres de notification de Telegram.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Clé Publique PGP", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Activer les Notifications", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Activer les Notifications", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "Email", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Les paramètres de notification Discord n’ont pas pu être enregistrés.", + "components.Settings.serviceSettingsDescription": "Configurez votre serveur {serverType} ci-dessous. Vous pouvez connecter plusieurs serveurs {serverType}, mais seulement deux d’entre eux peuvent être marqués par défaut (un non-4K et un 4K). Les administrateurs peuvent outrepasser le serveur utilisé pour traiter les nouvelles demandes avant l’approbation.", + "components.Settings.mediaTypeSeries": "séries", + "components.Settings.mediaTypeMovie": "film", + "components.Settings.SettingsAbout.uptodate": "À jour", + "components.Settings.SettingsAbout.outofdate": "Obsolète", + "components.Settings.Notifications.validationPgpPrivateKey": "Vous devez fournir une clé privée PGP valide si un mot de passe PGP est entré", + "components.Settings.Notifications.validationPgpPassword": "Vous devez fournir un mot de passe PGP si une clé privée PGP est saisie", + "components.Settings.Notifications.botUsernameTip": "Permettre aux utilisateurs de démarrer une conversation avec le bot et de configurer leurs propres notifications personnelles", + "components.RequestModal.pendingapproval": "Votre demande est en attente d’approbation.", + "components.RequestList.RequestItem.mediaerror": "Le titre associé à cette demande n’est plus disponible.", + "components.RequestList.RequestItem.deleterequest": "Supprimer la Demande", + "components.RequestList.RequestItem.cancelRequest": "Annuler la Demande", + "components.RequestCard.mediaerror": "Le titre associé à cette demande n’est plus disponible.", + "components.RequestCard.deleterequest": "Supprimer la Demande", + "components.NotificationTypeSelector.notificationTypes": "Types de Notification", + "components.Layout.VersionStatus.streamstable": "Overseerr Stable", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Develop", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} en retard", + "components.Layout.VersionStatus.outofdate": "Obsolète", + "components.Discover.noRequests": "Aucune demande.", + "components.RequestModal.QuotaDisplay.requiredquota": "Vous devez avoir au moins {seasons} {seasons, plural, one {demande de saison} other {demandes de saisons}} afin de soumettre une demande pour cette série.", + "components.RequestModal.QuotaDisplay.requiredquotaUser": "Cet utilisateur doit avoir au moins {seasons} {seasons, plural, one {demande de saison} other {demandes de saisons}} afin de soumettre une demande pour cette série.", + "components.Settings.noDefaultNon4kServer": "Si vous n’avez qu’un seul serveur {serverType} pour les contenus non-4K et 4K (ou si vous ne téléchargez que du contenu 4K), votre serveur {serverType} ne devrait PAS être désigné comme serveur 4K.", + "components.Settings.noDefaultServer": "Au moins un serveur {serverType} doit être marqué par défaut pour que les demandes {mediaType} puissent être envoyées.", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Paramètres de notification Discord enregistrés avec succès !", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Impossible d’enregistrer les paramètres de notification par Email.", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Paramètres de notification par Email enregistrés avec succès !", + "i18n.showingresults": "Affichage de {from} à {to} pour {total} résultats", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Activer les Mentions" } diff --git a/src/i18n/locale/hu.json b/src/i18n/locale/hu.json index bca00a32..52570312 100644 --- a/src/i18n/locale/hu.json +++ b/src/i18n/locale/hu.json @@ -83,7 +83,6 @@ "components.Login.password": "Jelszó", "components.Login.loginerror": "Valami nem sikerült a bejelentkezés során.", "components.Login.email": "Email cím", - "components.Layout.alphawarning": "Ez egy ALPHA szoftver. Előfordulhat, hogy egy-egy funkció hibásan működik vagy instabil. Kérlek jelentsd a problémákat GitHub-on!", "components.Layout.UserDropdown.signout": "Kijelentkezés", "components.Layout.Sidebar.users": "Felhasználók", "components.Layout.Sidebar.settings": "Beállítások", @@ -97,7 +96,6 @@ "components.Discover.recentlyAdded": "Nemrég hozzáadva", "components.Discover.populartv": "Népszerű sorozatok", "components.Discover.popularmovies": "Népszerű filmek", - "components.Discover.nopending": "Nincs függőben lévő kérés", "components.Discover.discovertv": "Népszerű sorozatok", "components.Discover.discovermovies": "Népszerű filmek", "components.CollectionDetails.requestcollection": "Gyűjtemény kérése", @@ -138,7 +136,6 @@ "components.NotificationTypeSelector.mediaavailableDescription": "Értesítést küld amikor a kért tartalom elérhetővé válik.", "components.NotificationTypeSelector.mediaavailable": "Kérés elérhető", "components.NotificationTypeSelector.mediaapproved": "Kérés elfogadva", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Értesítések típusai", "components.RequestButton.declinerequests": "{requestCount} kérés visszautasítása", "components.RequestButton.approverequests": "{requestCount} kérés jóváhagyása", "components.RequestButton.approve4krequests": "{requestCount} 4K kérés jóváhagyása", @@ -178,7 +175,6 @@ "components.UserList.role": "Jogosultság", "components.UserList.plexuser": "Plex felhasználó", "components.UserList.passwordinfodescription": "Az e-mail értesítéseket be kell állítani és engedélyezni kell a jelszavak automatikus generálásához.", - "components.UserList.passwordinfo": "Jelszó információ", "components.UserList.password": "Jelszó", "components.UserList.localuser": "Helyi felhasználó", "components.UserList.lastupdated": "Utoljára frissítve", @@ -246,7 +242,6 @@ "components.RequestModal.request4kfrom": "Jelenleg van egy függőben lévő kérés {username} felhasználótól.", "components.RequestModal.autoapproval": "Automatikus jóváhagyás", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Nem sikerült azonosítani a kérésed. Kérlek, válaszd ki a megfelelő találatot az alábbi listából:", - "components.RequestModal.SearchByNameModal.notvdbid": "Kézi azonosítás szükséges", "components.RequestBlock.profilechanged": "Profil megváltoztatva", "components.NotificationTypeSelector.mediarequestedDescription": "Értesítést küld új kérések elküldésekor.", "components.PermissionEdit.viewrequests": "Kérések megtekintése", diff --git a/src/i18n/locale/it.json b/src/i18n/locale/it.json index 4e403666..5cdf4db0 100644 --- a/src/i18n/locale/it.json +++ b/src/i18n/locale/it.json @@ -3,7 +3,6 @@ "components.Discover.recentlyAdded": "Aggiunti di recente", "components.Discover.populartv": "Serie popolari", "components.Discover.popularmovies": "Film popolari", - "components.Discover.nopending": "Nessuna richiesta in sospeso", "components.Discover.discovertv": "Serie popolari", "components.Discover.discovermovies": "Film popolari", "components.Settings.Notifications.emailsettingssaved": "Impostazioni delle notifiche via posta elettronica salvate con successo!", @@ -45,13 +44,12 @@ "components.MovieDetails.originallanguage": "Lingua originale", "components.MovieDetails.manageModalTitle": "Gestisci film", "components.MovieDetails.manageModalRequests": "Richieste", - "components.MovieDetails.manageModalNoRequests": "Nessuna richiesta", + "components.MovieDetails.manageModalNoRequests": "Nessuna richiesta.", "components.MovieDetails.manageModalClearMediaWarning": "* Questo rimuoverà irreversibilmente tutti i dati per questo film, incluse le richieste. Se questo elemento esiste nella tua libreria Plex, le informazioni saranno ricreate durante la prossima scansione.", "components.MovieDetails.manageModalClearMedia": "Cancella tutti i dati", "components.MovieDetails.cast": "Cast", "components.MovieDetails.budget": "Budget", "components.MovieDetails.MovieCast.fullcast": "Cast completo", - "components.Layout.alphawarning": "Questo è un software in ALPHA. Alcuni componenti potrebbero smettere di funzionare correttamente. Aiutaci segnalando ogni problema su GitHub!", "components.Layout.UserDropdown.signout": "Esci", "components.Layout.Sidebar.users": "Utenti", "components.Layout.Sidebar.settings": "Impostazioni", @@ -61,7 +59,7 @@ "components.Discover.upcomingmovies": "Film in uscita", "components.Discover.upcoming": "Film in uscita", "components.Discover.trending": "Di tendenza", - "components.UserList.deleteconfirm": "Eliminare l'utente? Tutti i dati di richiesta esistenti da questo utente verranno rimossi.", + "components.UserList.deleteconfirm": "Sei sicuro di voler rimuovere questo utente? Tutti le richieste verranno rimosse permanentemente.", "components.UserList.created": "Creato", "components.UserList.admin": "Amministratore", "components.UserList.role": "Ruolo", @@ -105,7 +103,7 @@ "components.Layout.Sidebar.dashboard": "Esplora", "components.TvDetails.manageModalTitle": "Gestisci serie", "components.TvDetails.manageModalRequests": "Richieste", - "components.TvDetails.manageModalNoRequests": "Nessuna richiesta", + "components.TvDetails.manageModalNoRequests": "Nessuna richiesta.", "components.TvDetails.manageModalClearMedia": "Cancella tutti i dati multimediali", "components.TvDetails.cast": "Cast", "components.TvDetails.anime": "Anime", @@ -121,10 +119,7 @@ "components.Settings.radarrsettings": "Impostazioni Radarr", "components.Settings.plexsettings": "Impostazioni Plex", "components.Settings.notrunning": "Non in esecuzione", - "components.Settings.notificationsettingsDescription": "Configura le impostazioni di notifiche globali. Le opzioni seguenti si applicheranno a tutti gli agenti di notifiche.", "components.Settings.notificationsettings": "Impostazioni delle notifiche", - "components.Settings.nodefaultdescription": "Almeno un server deve essere contrassegnato come predefinito prima che qualsiasi richiesta lo apportare ai servizi.", - "components.Settings.nodefault": "Nessun server predefinito", "components.Settings.menuServices": "Servizi", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuNotifications": "Notifiche", @@ -203,7 +198,7 @@ "components.Settings.Notifications.webhookUrlPlaceholder": "Impostazioni server → integrazioni → Webhook", "components.Settings.Notifications.webhookUrl": "URL webhook", "components.Settings.Notifications.validationSmtpPortRequired": "È necessario fornire un numero di porta valido", - "components.Settings.Notifications.validationSmtpHostRequired": "È necessario fornire un hostname o un indirizzo IP", + "components.Settings.Notifications.validationSmtpHostRequired": "È necessario fornire un hostname o un indirizzo IP valido", "components.Settings.Notifications.smtpPort": "Porta SMTP", "components.Settings.Notifications.smtpHost": "Host SMTP", "components.Settings.Notifications.enableSsl": "Abilita SSL", @@ -223,8 +218,6 @@ "components.TvDetails.manageModalClearMediaWarning": "* Questo rimuoverà irreversibilmente tutti i dati per questa serie TV, incluse eventuali richieste. Se questo elemento esiste nella tua libreria Plex, le informazioni dei media saranno ricreate durante la prossima scansione.", "components.Setup.signinMessage": "Comincia accedendo con il tuo account Plex", "components.Settings.sonarrsettings": "Impostazioni Sonarr", - "components.Settings.sonarrSettingsDescription": "Configura Sonarr qui sotto. È possibile avere più istanze, ma solo due attive contemporaneamente (uno per l'HD standard e uno per 4K). Gli amministratori possono forzare quale server utilizzare per le nuove richieste.", - "components.Settings.radarrSettingsDescription": "Configura Radarr qui sotto. È possibile avere più istanze, ma solo due attive contemporaneamente (uno per l'HD standard e uno per 4K). Gli amministratori possono forzare quale server utilizzare per le nuove richieste.", "components.Settings.plexsettingsDescription": "Configura le impostazioni del tuo server Plex. Overseerr scansiona Plex a intervalli regolari alla ricerca di nuovi contenuti.", "components.Settings.plexlibrariesDescription": "Le librerie che Overseerr scansiona alla ricerca di titoli. Se non ci sono librerie, configura e salva le impostazioni di connessione a Plex e fai click sul pulsante qui sotto.", "components.Settings.plexlibraries": "Librerie Plex", @@ -248,12 +241,11 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Visualizza il registro modifiche", "components.Settings.SettingsAbout.Releases.versionChangelog": "Registro versione", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "Le ultime modifiche di Overserr develop non sono mostrate di seguito. Consulta GitHub per maggiori dettagli.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Versione di Sviluppo", "components.Settings.SettingsAbout.Releases.releases": "Versioni", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Dati di versione non disponibili. GitHub è down?", "components.Settings.SettingsAbout.Releases.latestversion": "Versione più recente", "components.Settings.SettingsAbout.Releases.currentversion": "Versione attuale", - "components.Settings.Notifications.testsent": "Notifica di prova inviata!", + "components.Settings.Notifications.testsent": "Notifica Telegram di prova inviata!", "components.UserList.importfromplexerror": "Qualcosa è andato storto nell'importare gli utenti da Plex.", "components.UserList.importfromplex": "Importa utenti da Plex", "components.UserList.importedfromplex": "{userCount, plural, one {# nuovo utente} other {# nuovi utenti}} importati da Plex correttamente!", @@ -277,11 +269,10 @@ "i18n.retry": "Riprova", "i18n.failed": "Fallito", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL webhook", - "components.Settings.Notifications.NotificationsSlack.testsent": "Notifica di prova inviata!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Notifica Slack di prova inviata!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Impostazioni di Slack salvate con successo!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Impossibile salvare le impostazioni di Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Per configurare le notifiche con Slack, sarà necessario creare un'integrazione con un Webhook in ingresso e utilizzare l'URL del webhook fornito di seguito.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Impostazione delle notifiche di Slack", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Abilita Agente", "components.Settings.Notifications.validationChatIdRequired": "È necessario fornire un ID della discussione valido", "components.Settings.Notifications.validationBotAPIRequired": "Devi fornire un token di autenticazione del bot", @@ -289,15 +280,12 @@ "components.Settings.Notifications.telegramsettingsfailed": "Impossibile salvare le impostazioni di Telegram.", "components.Settings.Notifications.senderName": "Nome del mittente", "components.Settings.Notifications.settinguptelegramDescription": "Per configurare le notifiche di Telegram, dovrai creare un bot e ottenerne la chiave API. Inoltre, avrai bisogno dell'ID della chat a cui volete inviare le notifiche. Puoi trovarlo aggiungendo @get_id_bot alla chat ed inserendo il comando /my_id.", - "components.Settings.Notifications.settinguptelegram": "Configurazione delle notifiche di Telegram", "components.Settings.Notifications.chatId": "ID chat", "components.Settings.Notifications.botAPI": "Token di autenticazione bot", "components.StatusChacker.reloadOverseerr": "Ricarica", "components.StatusChacker.newversionavailable": "Aggiornamento Applicazione", "components.StatusChacker.newversionDescription": "Overseerr è stato aggiornato! Premi il pulsante qui sotto per ricaricare la pagina.", "components.Settings.SettingsAbout.documentation": "Documentazione", - "components.Settings.Notifications.notificationtypes": "Tipi di notifica", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Tipi di notifica", "components.NotificationTypeSelector.mediarequestedDescription": "Invia una notifica quando i media sono richiesti e richiedono l'approvazione.", "components.NotificationTypeSelector.mediarequested": "Media Richiesto", "components.NotificationTypeSelector.mediafailedDescription": "Invia una notifica quando il media non viene aggiunto a Radarr o Sonarr.", @@ -309,13 +297,11 @@ "i18n.request": "Richiedi", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "È necessario fornire una chiave utente valida", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "È necessario fornire un token di applicazione valido", - "components.Settings.Notifications.NotificationsPushover.userToken": "Chiave utente", - "components.Settings.Notifications.NotificationsPushover.testsent": "Notifica di prova inviata!", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Per configurare le notifiche con Pushover, è necessario registrare un'applicazione e inserire il token API qui sotto. (Puoi usare una delle nostre icone ufficiali su GitHub.) Avrai anche bisogno della tua chiave utente.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Impostazione delle notifiche di Pushover", + "components.Settings.Notifications.NotificationsPushover.userToken": "Chiave utente o di gruppo", + "components.Settings.Notifications.NotificationsPushover.testsent": "Notifica Pushover di prova inviata!", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Per configurare le notifiche con Pushover, è necessario registrare un'applicazione e inserire il token API qui sotto. (Puoi usare una delle icone ufficiali su GitHub.)", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Impostazioni di Pushover salvate con successo!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Impossibile salvare le impostazioni di Pushover.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Tipi di notifica", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Abilita Agente", "components.Settings.Notifications.NotificationsPushover.accessToken": "Token di API/applicazione", "components.RequestList.sortModified": "Ultima modifica", @@ -333,7 +319,6 @@ "components.UserList.createlocaluser": "Crea un utente locale", "components.UserList.create": "Crea", "components.UserList.autogeneratepassword": "Genera automaticamente la password", - "components.UserList.passwordinfo": "Informazioni sulla password", "components.UserList.password": "Password", "components.UserList.localuser": "Utente locale", "components.UserList.usercreatedsuccess": "Utente creato correttamente!", @@ -351,7 +336,7 @@ "components.Login.password": "Password", "components.Login.loginerror": "Qualcosa è andato storto durante il tentativo di accesso.", "components.Login.email": "Indirizzo e-mail", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Notifica di prova inviata!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Notifica Webhook di prova inviata!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Guida per variabili di modello", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Abilita Agente", "components.RequestModal.request4ktitle": "Richiedi {title} in 4K", @@ -372,7 +357,6 @@ "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "È necessario fornire un payload JSON valido", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "Payload JSON reimpostato correttamente!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Ripristino delle impostazioni predefinite", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Tipi di notifica", "components.Settings.Notifications.NotificationsWebhook.customJson": "Payload JSON", "components.RequestModal.requestedited": "Richiesta di {title} modificata correttamente!", "components.RequestModal.requestcancelled": "Richiesta per {title} eliminata.", @@ -388,9 +372,6 @@ "components.RequestModal.AdvancedRequester.advancedoptions": "Opzioni avanzate", "components.RequestButton.declinerequests": "Rifiuta {requestCount} {requestCount, plural, one {richiesta} other {richieste}}", "components.RequestBlock.requestoverrides": "Aggiramenti della richiesta", - "components.Settings.notificationsettingssaved": "Impostazioni delle notifiche salvate correttamente!", - "components.Settings.notificationsettingsfailed": "Impossibile salvare le impostazioni di notifiche.", - "components.Settings.notificationAgentsSettings": "Agenti di notifica", "components.UserList.bulkedit": "Modifica collettiva", "components.UserList.userssaved": "Permessi salvati con successo!", "components.PermissionEdit.vote": "Voto", @@ -419,15 +400,13 @@ "components.Login.forgotpassword": "Password dimenticata?", "components.Discover.discover": "Esplora", "components.AppDataWarning.dockerVolumeMissingDescription": "Il volume {appDataPath} non è configurato correttamente. Tutte le modifiche apportate saranno perse quando il container verrà interrotto o riavviato.", - "components.AppDataWarning.dockerVolumeMissing": "Volume Docker mancante", "components.Settings.serverpresetLoad": "Premi il pulsante per caricare i server disponibili", "components.Settings.serverpreset": "Server", "components.Settings.servernameTip": "Recuperato automaticamente da Plex dopo il salvataggio", "components.Settings.serverRemote": "remoto", "components.Settings.serverLocal": "locale", "components.Settings.serverConnected": "connesso", - "components.Settings.notificationAgentSettingsDescription": "Scegli i tipi di notifiche da inviare e quali agenti di notifica utilizzare.", - "components.Settings.enablenotifications": "Abilita notifiche", + "components.Settings.notificationAgentSettingsDescription": "Configura e abilita gli agenti di notifica.", "components.Settings.csrfProtectionTip": "Imposta l'accesso alle API esterne in sola lettura (richiede HTTPS e Overseerr deve essere ricaricato affinché le modifiche abbiano effetto)", "components.Settings.csrfProtectionHoverTip": "NON abilitate questa opzione se non sapete cosa state facendo!", "components.Settings.csrfProtection": "Abilita protezione CSRF", @@ -496,7 +475,6 @@ "components.ResetPassword.confirmpassword": "Conferma la password", "components.RequestModal.requesterror": "Qualcosa è andato storto durante l'invio della richiesta.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Non siamo riusciti a soddisfare automaticamente la tua richiesta. Seleziona la corrispondenza corretta dall'elenco seguente.", - "components.RequestModal.SearchByNameModal.notvdbid": "Abbinamento manuale richiesto", "components.RequestModal.SearchByNameModal.nosummary": "Non è stato trovato alcun riassunto per questo titolo.", "components.RequestModal.AdvancedRequester.requestas": "Richiedi come", "components.RequestModal.AdvancedRequester.languageprofile": "Profilo lingua", @@ -540,14 +518,13 @@ "components.Settings.toastPlexConnectingFailure": "Impossibile connettersi a Plex.", "components.Settings.toastPlexConnecting": "Tentativo di connessione a Plex…", "components.Settings.timeout": "Scadenza", - "components.Settings.settingUpPlex": "Configurazione di Plex", "components.Settings.serverpresetRefreshing": "Recupero di server…", "components.Settings.serverpresetPlaceholder": "Server Plex", "components.Settings.serverpresetManualMessage": "Configurazione manuale", "components.TvDetails.nextAirDate": "Prossima data di messa in onda", "components.TvDetails.mark4kavailable": "Segna 4K come disponibile", "components.Settings.trustProxyTip": "Permette a Overseerr di registrare correttamente gli indirizzi IP dei client dietro un proxy (Overseerr deve essere ricaricato perché le modifiche abbiano effetto)", - "components.Settings.settingUpPlexDescription": "Per impostare Plex, potete inserire i vostri dati manualmente o selezionare un server recuperato da plex.tv. Premi il pulsante a destra del menu a tendina per controllare la connettività e recuperare i server disponibili.", + "components.Settings.settingUpPlexDescription": "Per impostare Plex, potete inserire i vostri dati manualmente o selezionare un server recuperato da plex.tv. Premi il pulsante a destra del menu a tendina per recuperare la lista di server disponibili.", "components.Settings.Notifications.sendSilentlyTip": "Invia notifiche senza suono", "components.Settings.Notifications.sendSilently": "Invia silenziosamente", "components.UserList.sortCreated": "Data di creazione", @@ -560,12 +537,10 @@ "components.PermissionEdit.autoapprove4kSeriesDescription": "Concede l'approvazione automatica per le richieste di serie in 4K fatte da questo utente.", "components.PermissionEdit.autoapprove4kSeries": "Auto-approva le serie in 4K", "components.PermissionEdit.autoapprove4kDescription": "Concede l'approvazione automatica per tutte le richieste 4K fatte da questo utente.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Questo account utente attualmente non dispone di una password specifica per {applicationTitle}. Configura una password di seguito per consentire a questo account di accedere come «utente locale».", "components.Layout.UserDropdown.myprofile": "Profilo", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Impostazioni Notifiche", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Abilita Notifiche", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "ID utente del tuo account Discord", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "ID utente del tuo account", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID utente", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Impostazioni salvate con successo!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Qualcosa è andato storto nel salvare le impostazioni.", "components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Utente Plex", @@ -577,13 +552,11 @@ "components.UserList.userfail": "Qualcosa è andato storto durante il salvataggio dei permessi.", "components.UserList.edituser": "Modifica le autorizzazioni dell'utente", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "È necessario fornire un token di accesso", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notifica di prova inviata!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Per configurare le notifiche di Pushbullet, sarà necessario creare un token di accesso e immetterlo di seguito.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configurazione delle notifiche di Pushover", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notifica Pushbullet di prova inviata!", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Per configurare le notifiche di Pushbullet, sarà necessario creare un token di accesso.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Impostazioni di Pushover salvate correttamente!", "components.Layout.UserDropdown.settings": "Impostazioni", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Impossibile salvare le impostazioni di Pushbullet.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Tipi di Notifica", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Abilita Agente", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Token di accesso", "components.UserProfile.recentrequests": "Richieste Recenti", @@ -602,11 +575,10 @@ "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Password salvata correttamente!", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Qualcosa è andato storto durante il salvataggio della password.", "components.UserProfile.UserSettings.UserPasswordChange.password": "Password", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Nessuna password impostata", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nuova password", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Password attuale", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Conferma la password", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "È necessario fornire un ID utente di Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "È necessario fornire un ID utente valido", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Impostazioni salvate correttamente!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Qualcosa è andato storto nel salvare le impostazioni.", "components.CollectionDetails.requestswillbecreated4k": "Per i titoli seguenti verranno create richieste per 4K:", @@ -617,7 +589,6 @@ "components.Settings.region": "Regione da scoprire", "components.Settings.originallanguage": "Lingua da scoprire", "components.Settings.email": "E-mail", - "components.Settings.Notifications.emailNotificationTypesAlert": "Destinatari delle notifiche via posta elettronica", "components.RegionSelector.regionDefault": "Tutte le regioni", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filtra i contenuti per disponibilità regionale", "components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filtra i contenuti per lingua originale", @@ -638,12 +609,11 @@ "components.Discover.DiscoverMovieGenre.genreMovies": "Film di {genre}", "components.Settings.SettingsJobsCache.download-sync-reset": "Reimposta sincronizzazione di scaricamento", "i18n.loading": "Caricamento…", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Devi fornire un ID valido per la discussione di Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "È necessario fornire un ID chat valido", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Inizia una chat, aggiungi @get_id_bot, ed esegui il comando /my_id", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Aggiungi @get_id_bot alla chat", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID chat di Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID chat", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Invia notifiche senza suono", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Invia messaggi con Telegram silenziosamente", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Invia silenziosamente", "components.TvDetails.seasons": "{seasonCount, plural, one {# Stagione} other {# Stagioni}}", "components.Settings.SettingsJobsCache.unknownJob": "Task sconosciuto", "components.Settings.SettingsJobsCache.download-sync": "Scarica sincronizzazione", @@ -678,16 +648,15 @@ "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Le notifiche via posta elettronica Media approvato, Media rifiutato, e Media disponibile sono inviate all'utente che ha effettuato la richiesta.", "components.NotificationTypeSelector.mediaAutoApprovedDescription": "Invia una notifica quando i media richiesti vengono approvati automaticamente.", "components.NotificationTypeSelector.mediaAutoApproved": "Media approvati automaticamente", - "components.Settings.Notifications.pgpPrivateKey": "Chiave privata PGP", - "components.Settings.Notifications.pgpPasswordTip": "Firma i messaggi di posta elettronica crittografati (è richiesta anche la chiave privata PGP)", - "components.Settings.Notifications.pgpPassword": "Password PGP", + "components.Settings.Notifications.pgpPrivateKey": "Chiave privata PGP", + "components.Settings.Notifications.pgpPasswordTip": "Firma i messaggi di posta elettronica crittografati utilizzando OpenPGP ", + "components.Settings.Notifications.pgpPassword": "Password PGP", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.Discover.TvGenreSlider.tvgenres": "Generi Serie", "components.Discover.MovieGenreSlider.moviegenres": "Generi film", - "components.UserProfile.norequests": "Nessuna richiesta", + "components.UserProfile.norequests": "Nessuna richiesta.", "components.UserProfile.UserSettings.unauthorizedDescription": "Non hai l'autorizzazione per modificare le impostazioni di questo utente.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "Non è possibile modificare le proprie autorizzazioni.", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP chiave pubblica", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minuti", "components.TvDetails.episodeRuntime": "Durata di un episodio", "components.Settings.partialRequestsEnabled": "Consente richieste di serie parziali", @@ -695,8 +664,7 @@ "components.RequestModal.alreadyrequested": "Già richiesto", "components.Discover.TvGenreList.seriesgenres": "Generi serie", "components.Discover.MovieGenreList.moviegenres": "Generi film", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Crittografa i messaggi di posta elettronica", - "components.Settings.Notifications.pgpPrivateKeyTip": "Firma messaggi di posta elettronica crittografati (la password PGP è anche richiesta)", + "components.Settings.Notifications.pgpPrivateKeyTip": "Firma i messaggi di posta elettronica crittografati utilizzando OpenPGP ", "pages.somethingwentwrong": "Qualcosa è andato storto", "pages.serviceunavailable": "Servizio non disponibile", "pages.pagenotfound": "Pagina non trovata", @@ -705,7 +673,6 @@ "i18n.usersettings": "Impostazioni utente", "i18n.settings": "Impostazioni", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Qualcosa è andato storto durante il salvataggio della password. La password attuale è stata inserita correttamente?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Il tuo account attualmente non dispone di una password specifica per {applicationTitle}. Configura una password di seguito per abilitare l'accesso come «utente locale» utilizzando il tuo indirizzo e-mail.", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notifiche", "components.UserProfile.UserSettings.UserGeneralSettings.general": "Generali", "components.Settings.services": "Servizi", @@ -734,7 +701,7 @@ "components.Settings.enablessl": "Abilita SSL", "components.Settings.SettingsLogs.logDetails": "Dettagli registro", "components.Settings.SettingsLogs.extraData": "Dati aggiuntivi", - "components.Settings.SettingsLogs.copyToClipboard": "Copia negli Appunti", + "components.Settings.SettingsLogs.copyToClipboard": "Copia negli appunti", "components.Settings.SettingsLogs.copiedLogMessage": "Messaggio di registro copiato negli appunti.", "components.UserList.nouserstoimport": "Nessun nuovo utente da importare da Plex.", "components.PersonDetails.lifespan": "{birthdate} – {deathdate}", @@ -743,7 +710,6 @@ "i18n.delimitedlist": "{a}, {b}", "components.MovieDetails.originaltitle": "Titolo Originale", "i18n.view": "Vista", - "i18n.unauthorized": "Non autorizzato", "i18n.tvshow": "Serie", "i18n.testing": "Test in corso…", "i18n.test": "Test", @@ -792,5 +758,47 @@ "components.QuotaSelector.tvRequestLimit": "{quotaLimit} stagione/i per {quotaDays} giorno/i", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} film per {quotaDays} giorno/i", "components.LanguageSelector.originalLanguageDefault": "Tutte le lingue", - "components.LanguageSelector.languageServerDefault": "({language}) predefinito" + "components.LanguageSelector.languageServerDefault": "Predefinito ({language})", + "components.Settings.SonarrModal.testFirstTags": "Verifica la connessione per caricare i tag", + "components.Settings.SonarrModal.tags": "Tag", + "components.Settings.SonarrModal.selecttags": "Seleziona i tag", + "components.Settings.SonarrModal.notagoptions": "Nessun tag.", + "components.Settings.SonarrModal.loadingTags": "Caricamento tag…", + "components.Settings.SonarrModal.edit4ksonarr": "Modifica server Sonarr 4K", + "components.Settings.SonarrModal.default4kserver": "Server 4K predefinito", + "components.Settings.SonarrModal.create4ksonarr": "Aggiungi un nuovo server Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Tag Anime", + "components.Settings.RadarrModal.testFirstTags": "Verifica la connessione per caricare i tag", + "components.Settings.RadarrModal.tags": "Tag", + "components.Settings.RadarrModal.selecttags": "Seleziona i tag", + "components.Settings.RadarrModal.notagoptions": "Nessun tag.", + "components.Settings.RadarrModal.loadingTags": "Caricamento tag…", + "components.Settings.RadarrModal.edit4kradarr": "Modifica server Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Server 4K predefinito", + "components.Settings.RadarrModal.create4kradarr": "Aggiungi un nuovo server Radarr 4K", + "components.RequestModal.AdvancedRequester.tags": "Tag", + "components.RequestModal.AdvancedRequester.selecttags": "Seleziona i tag", + "components.RequestModal.AdvancedRequester.notagoptions": "Nessun tag.", + "components.Discover.noRequests": "Nessuna richiesta.", + "components.Layout.VersionStatus.outofdate": "Non aggiornato", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {versione} other {versioni}} indietro", + "components.Settings.serviceSettingsDescription": "Configura i tuoi server {serverType} qui sotto. Puoi collegare più server {serverType}, ma solo due possono essere contrassegnati come predefiniti (uno non-4K e uno 4K). Gli amministratori possono selezionare il server usato per elaborare le nuove richieste prima dell'approvazione.", + "components.Settings.noDefaultServer": "Almeno un server {serverType} deve essere contrassegnato come predefinito affinché le richieste {mediaType} possano essere processate.", + "components.Settings.noDefaultNon4kServer": "Se hai solo un singolo server {serverType} per contenuti non-4K e 4K (o se scarichi solo contenuti 4K), il tuo server {serverType} NON dovrebbe essere designato come server 4K.", + "components.Settings.mediaTypeSeries": "serie", + "components.Settings.mediaTypeMovie": "film", + "components.Settings.SettingsAbout.uptodate": "Aggiornato", + "components.Settings.SettingsAbout.outofdate": "Non aggiornato", + "components.Settings.Notifications.validationPgpPrivateKey": "È necessario fornire una chiave privata PGP valida se viene immessa una password PGP", + "components.Settings.Notifications.validationPgpPassword": "È necessario fornire una password PGP se viene immessa una chiave privata PGP", + "components.Settings.Notifications.botUsernameTip": "Consenti agli utenti di avviare una chat con il bot e configurare le proprie notifiche personali", + "components.RequestModal.pendingapproval": "La richiesta è in attesa di approvazione.", + "components.RequestList.RequestItem.mediaerror": "Il titolo associato a questa richiesta non è più disponibile.", + "components.RequestList.RequestItem.deleterequest": "Elimina Richiesta", + "components.RequestList.RequestItem.cancelRequest": "Annulla Richiesta", + "components.RequestCard.mediaerror": "Il titolo associato a questa richiesta non è più disponibile.", + "components.RequestCard.deleterequest": "Elimina Richiesta", + "components.NotificationTypeSelector.notificationTypes": "Tipi di Notifica", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Beta", + "components.Layout.VersionStatus.streamstable": "Overseerr Stabile" } diff --git a/src/i18n/locale/ja.json b/src/i18n/locale/ja.json index b1e723fd..154c610e 100644 --- a/src/i18n/locale/ja.json +++ b/src/i18n/locale/ja.json @@ -1,7 +1,6 @@ { "components.Discover.discovermovies": "人気の映画", "components.Discover.discovertv": "人気のテレビ番組", - "components.Discover.nopending": "保留中のリクエストがありません", "components.Discover.popularmovies": "人気の映画", "components.Discover.populartv": "人気のテレビ番組", "components.Discover.recentlyAdded": "最近追加された動画", @@ -16,7 +15,6 @@ "components.Layout.Sidebar.settings": "設定", "components.Layout.Sidebar.users": "ユーザー", "components.Layout.UserDropdown.signout": "ログアウト", - "components.Layout.alphawarning": "このソフトはアルファ版です。ほとんどの機能は不安定又は故障している可能性があります。バグを発見した場合、Overseerr の Github までご連絡ください!", "components.MovieDetails.budget": "予算", "components.MovieDetails.cast": "出演者", "components.MovieDetails.manageModalClearMedia": "メディア情報を消去", @@ -140,18 +138,15 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "連携サービス", "components.Settings.notificationsettings": "通知設定", - "components.Settings.notificationsettingsDescription": "ここでは、どのような通知を送信する又はどのサービスを使って送信するかを設定できます。", "components.Settings.notrunning": "実行されていない", "components.Settings.plexlibraries": "Plex ライブラリー", "components.Settings.plexlibrariesDescription": "Overseerr がスキャンしてタイトルを探すライブラリ。リストにない場合、Plex の接続設定を保存し、下のボタンをクリックしてください。", "components.Settings.plexsettings": "Plex の設定", "components.Settings.plexsettingsDescription": "Plex サーバーの設定。Overseerr は、Plex サーバーを使用して、間隔をおいてライブラリをスキャンし、利用可能なコンテンツを確認します。", "components.Settings.port": "ポート", - "components.Settings.radarrSettingsDescription": "Radarr 接続設定。複数のサーバーを繋ぐことができますが、デフォルトで常にアクティブなのは 2 つのみ(1 つは標準 HD 用、もう 1 つは 4K 用)。管理者は、新しいリクエストに使用するサーバーを選択することができます。", "components.Settings.radarrsettings": "Radarr 設定", "components.Settings.servername": "サーバー名", "components.Settings.servernamePlaceholder": "Plex サーバー名", - "components.Settings.sonarrSettingsDescription": "Sonarr 接続設定。複数のサーバーを繋ぐことができますが、デフォルトで常にアクティブなのは 2 つのみ(1 つは標準 HD 用、もう1つは 4K 用)。管理者は、新しいリクエストに使用するサーバーを選択することができます。", "components.Settings.sonarrsettings": "Sonarr 設定", "components.Settings.ssl": "SSL", "components.Settings.startscan": "スキャンを開始", @@ -226,8 +221,6 @@ "components.Settings.toastSettingsFailure": "設定保存中に問題が発生しました。", "components.Settings.toastApiKeySuccess": "新しい API キーが生成されました!", "components.Settings.toastApiKeyFailure": "新しい API キーの生成中に問題が発生しました。", - "components.Settings.nodefaultdescription": "サービスへのリクエストを行う前に、一つのサーバーをデフォルトとして設定する必要があります。", - "components.Settings.nodefault": "デフォルトサーバーが選択されていません", "components.Settings.SonarrModal.testFirstRootFolders": "ルートフォルダーをロードするには先に接続をテストしてください", "components.Settings.SonarrModal.testFirstQualityProfiles": "画質プロファイルをロードするには先に接続をテストしてください", "components.Settings.SonarrModal.loadingrootfolders": "ルートフォルダー読込中…", @@ -248,7 +241,6 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "変更履歴参照", "components.Settings.SettingsAbout.Releases.versionChangelog": "バージョン変更履歴", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "お使いのバージョンのパッチノート以下に記載されていません。最新のアップデートはGitHubリポジトリをご覧ください。", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Overseerrの開発バージョンを実行しています!", "components.Settings.SettingsAbout.Releases.releases": "リリース", "components.Settings.SettingsAbout.Releases.releasedataMissing": "リリースデータがありません。GitHub はダウンしていますか?", "components.Settings.SettingsAbout.Releases.latestversion": "最新", @@ -280,7 +272,6 @@ "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slackの通知設定が保存されました", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack の通知設定の保存に失敗しました。", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Slack 通知を使用するには、受信ウェブフックを作成し、以下の webhook URL を使用する必要があります。", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Slack 通知の設定", "components.Login.signin": "ログイン", "components.Login.password": "パスワード", "components.Login.loginerror": "ログイン中に問題が発生しました。", @@ -292,7 +283,6 @@ "components.CollectionDetails.requestswillbecreated4k": "以下のタイトルの 4K のリクエストをします:", "components.CollectionDetails.requestcollection4k": "4K のコレクションをリクエスト", "components.AppDataWarning.dockerVolumeMissingDescription": "{appDataPath} ボリュームマウントが正しく構成されていませんでした。コンテナーが停止または再起動されると、すべてのデータが消去されます。", - "components.AppDataWarning.dockerVolumeMissing": "Docker ボリュームマウントがありません", "components.PlexLoginButton.signingin": "ログイン中…", "components.Login.signingin": "ログイン中…", "components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "設定保存中に問題が発生しました。", @@ -357,5 +347,7 @@ "i18n.loading": "ロード中…", "i18n.testing": "テスト中…", "i18n.test": "テストする", - "i18n.status": "状態" + "i18n.status": "状態", + "components.TvDetails.originaltitle": "原題", + "components.MovieDetails.originaltitle": "原題" } diff --git a/src/i18n/locale/nb_NO.json b/src/i18n/locale/nb_NO.json index 7ed5cc5d..5e3fbaa5 100644 --- a/src/i18n/locale/nb_NO.json +++ b/src/i18n/locale/nb_NO.json @@ -1,7 +1,6 @@ { "components.Discover.discovermovies": "Populære filmer", "components.Discover.discovertv": "Populære serier", - "components.Discover.nopending": "Ingen ventende forespørsler", "components.Discover.popularmovies": "Populære filmer", "components.Discover.populartv": "Populære serier", "components.Discover.recentlyAdded": "Nylig lagt til", @@ -16,7 +15,6 @@ "components.Layout.Sidebar.settings": "Innstillinger", "components.Layout.Sidebar.users": "Brukere", "components.Layout.UserDropdown.signout": "Logg ut", - "components.Layout.alphawarning": "Dette er programvare i alfa-stadie. Nesten alt vil være ufunksjonelt eller ustabilt. Rapporter feil til Overseerr på GitHub.", "components.MovieDetails.budget": "Budsjett", "components.MovieDetails.cast": "Roller", "components.MovieDetails.manageModalClearMedia": "Tøm all mediedata", @@ -71,7 +69,7 @@ "components.Settings.RadarrModal.createradarr": "Legg til ny Radarr-tjener", "components.Settings.RadarrModal.defaultserver": "Forvalgt tjener", "components.Settings.RadarrModal.editradarr": "Rediger Radarr-tjener", - "components.Settings.RadarrModal.hostname": "Vertsnavn", + "components.Settings.RadarrModal.hostname": "Vertsnavn eller IP-adresse", "components.Settings.RadarrModal.minimumAvailability": "Minimumstilgjengelighet", "components.Settings.RadarrModal.port": "Port", "components.Settings.RadarrModal.qualityprofile": "Kvalitetsprofil", @@ -95,25 +93,25 @@ "components.Settings.SonarrModal.apiKeyPlaceholder": "Din API-nøkkel for Sonarr", "components.Settings.SonarrModal.baseUrl": "Grunn-URL", "components.Settings.SonarrModal.baseUrlPlaceholder": "Eksempel: /sonarr", - "components.Settings.SonarrModal.createsonarr": "Opprett ny Sonarr-tjener", + "components.Settings.SonarrModal.createsonarr": "Legg til ny Sonarr-tjener", "components.Settings.SonarrModal.defaultserver": "Forvalgt tjener", "components.Settings.SonarrModal.editsonarr": "Rediger Sonarr-tjener", - "components.Settings.SonarrModal.hostname": "Vertsnavn", + "components.Settings.SonarrModal.hostname": "Vertsnavn eller IP-adresse", "components.Settings.SonarrModal.port": "Port", "components.Settings.SonarrModal.qualityprofile": "Kvalitetsprofil", "components.Settings.SonarrModal.rootfolder": "Grunnmappe", "components.Settings.SonarrModal.seasonfolders": "Sesongmapper", "components.Settings.SonarrModal.selectQualityProfile": "Velg en kvalitetsprofil", - "components.Settings.SonarrModal.selectRootFolder": "Velg en rotmappe", + "components.Settings.SonarrModal.selectRootFolder": "Velg grunnmappe", "components.Settings.SonarrModal.server4k": "4K-tjener", "components.Settings.SonarrModal.servername": "Tjenernavn", "components.Settings.SonarrModal.servernamePlaceholder": "En Sonarr-tjener", - "components.Settings.SonarrModal.ssl": "SSL", - "components.Settings.SonarrModal.validationApiKeyRequired": "Du må angi en API-nøkkel", - "components.Settings.SonarrModal.validationHostnameRequired": "Du må angi vertsnavn/IP", - "components.Settings.SonarrModal.validationPortRequired": "Du må angi en port", - "components.Settings.SonarrModal.validationProfileRequired": "Du må velge en porfil", - "components.Settings.SonarrModal.validationRootFolderRequired": "Du må velge en rotmappe", + "components.Settings.SonarrModal.ssl": "Aktiver SSL", + "components.Settings.SonarrModal.validationApiKeyRequired": "Du må oppgi en API-nøkkel", + "components.Settings.SonarrModal.validationHostnameRequired": "Du må oppgi et vertsnavn eller en IP-adresse", + "components.Settings.SonarrModal.validationPortRequired": "Du må oppgi et gyldig portnummer", + "components.Settings.SonarrModal.validationProfileRequired": "Du må velge en kvalitetsprofil", + "components.Settings.SonarrModal.validationRootFolderRequired": "Du må velge en grunnmappe", "components.Settings.activeProfile": "Aktiv profil", "components.Settings.addradarr": "Legg til Radarr-tjener", "components.Settings.address": "Adresse", @@ -128,30 +126,27 @@ "components.Settings.deleteserverconfirm": "Er du sikker på at du vil slette denne tjeneren?", "components.Settings.generalsettings": "Generelle innstilinger", "components.Settings.generalsettingsDescription": "Dette er innstillinger som har med det generelle Overseerr-oppsettet å gjøre.", - "components.Settings.hostname": "Vertsnavn/IP", + "components.Settings.hostname": "Vertsnavn eller IP-adresse", "components.Settings.librariesRemaining": "Bibliotek som gjenstår: {count}", "components.Settings.manualscan": "Manuell biblioteksskanning", "components.Settings.manualscanDescription": "Normalt vil dette kun kjøres hver sjette time. Overseerr sjekker din Plex-tjeners nylige media mer aggresivt. Hvis dette er første gangen du setter opp Plex, anbefales en full manuell biblioteksskanning.", "components.Settings.menuAbout": "Om", - "components.Settings.menuGeneralSettings": "Generelle innstillinger", - "components.Settings.menuJobs": "Jobber", + "components.Settings.menuGeneralSettings": "Generelt", + "components.Settings.menuJobs": "Jobber og cache", "components.Settings.menuLogs": "Logger", "components.Settings.menuNotifications": "Merknader", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "Tjenester", "components.Settings.notificationsettings": "Varselinnstillinger", - "components.Settings.notificationsettingsDescription": "Har kan du velge hvilke type merknader som skal sendes gjennom en del tjenester.", "components.Settings.notrunning": "Kjører ikke", "components.Settings.plexlibraries": "Plex-bibliotek", - "components.Settings.plexlibrariesDescription": "Bibliotekene Overseerr skanner for titler. Sett opp og lagre dine Plex-tilkoblingsinnstillinger og klikk på knappen nedenfor hvis ingen vises.", + "components.Settings.plexlibrariesDescription": "Bibliotekene Overseerr skanner for media. Sett opp og lagre dine Plex-tilkoblingsinnstillinger; klikk deretter på knappen under hvis ingen bibliotek vises.", "components.Settings.plexsettings": "Plex-innstillinger", "components.Settings.plexsettingsDescription": "Sett opp innstillingene for din Plex-tjener. Overseerr vil skanne de valgte bibliotekene på din Plex-tjener med jevne mellomrom for å se hvilket innhold som er tilgjengelig.", "components.Settings.port": "Port", - "components.Settings.radarrSettingsDescription": "Konfigurer din Radarr-tilkobling nedenfor. Du kan ha flere, men kun to aktive som forvalg (en for standard HD, og en for 4K). Administratorer kan overstyre hvilken tjener som brukes for nye forespørsler.", "components.Settings.radarrsettings": "Radarr-innstillinger", "components.Settings.servername": "Tjenernavn (automatisk valgt)", "components.Settings.servernamePlaceholder": "Plex-tjenernavn", - "components.Settings.sonarrSettingsDescription": "Konfigurer din Sonarr-tilkobling nedenfor. Du kan ha flere, men kun to aktive som forvalg (en for standard HD, og en for 4K). Administratorer kan overstyre hvilken tjener som brukes for nye forespørsler.", "components.Settings.sonarrsettings": "Sonarr-innstillinger", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Start skanning", @@ -198,10 +193,8 @@ "pages.oops": "Oida", "pages.returnHome": "Gå hjem", "pages.errormessagewithcode": "{statusCode} - {error}", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Krypter e-postmeldinger", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Varselinnstillinger", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Varsler", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Aktiver varsler", "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "ID-nummeret til din Discord-konto", "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord ID", "components.UserProfile.UserSettings.UserGeneralSettings.user": "Bruker", @@ -231,8 +224,8 @@ "components.Settings.SettingsUsers.userSettings": "Brukerinnstillinger", "components.Settings.SettingsUsers.toastSettingsSuccess": "Brukerinnstillinger lagret!", "components.Settings.SettingsUsers.toastSettingsFailure": "Noe gikk galt ved lagring av innstillinger.", - "components.Settings.SettingsUsers.localLogin": "Aktiver lokal brukerinnlogging", - "components.Settings.SettingsUsers.defaultPermissions": "Standard brukertilganger", + "components.Settings.SettingsUsers.localLogin": "Aktiver lokal innlogging", + "components.Settings.SettingsUsers.defaultPermissions": "Standard tilganger", "components.PermissionEdit.viewrequestsDescription": "Gi tilgang til å se andre brukere sine forespørsler.", "components.PermissionEdit.usersDescription": "Gi tilgang til å administrere brukere i Overseerr. Brukere med denne tilgangen har ikke mulighet til å endre brukertilganger eller gi administratortilgang.", "components.PermissionEdit.users": "Administrer brukere", @@ -260,8 +253,6 @@ "components.CollectionDetails.overview": "Oversikt", "components.CollectionDetails.numberofmovies": "{count} Filmer", "components.UserProfile.ProfileHeader.profile": "Vis profil", - "components.Settings.nodefaultdescription": "Minst én server må være satt som forvalgt sever før forespørsler vil bli sendt til dine tjenester.", - "components.Settings.nodefault": "Ingen Forvalgt Server", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Nullstill", "components.TvDetails.TvCast.fullseriescast": "Roller", "components.MovieDetails.MovieCast.fullcast": "Roller", @@ -269,10 +260,8 @@ "components.TvDetails.TvCrew.fullseriescrew": "Besetning", "components.MovieDetails.viewfullcrew": "Vis besetning", "components.MovieDetails.MovieCrew.fullcrew": "Besetning", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Setter opp Pushbullet-varsler", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Fikk ikke lagret Pushbullet-varselinnstillinger.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet-varselinnstillinger lagret!", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Varseltyper", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Aktiver Agent", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Tilgangspollett", "components.Search.search": "Søk", @@ -297,7 +286,6 @@ "components.RequestModal.pending4krequest": "Ventende forespørsel for {title} i 4K", "components.RequestModal.errorediting": "Noe gikk galt under endring av forespørselen.", "components.RequestModal.autoapproval": "Automatisk Godkjenning", - "components.RequestModal.SearchByNameModal.notvdbid": "Manuell kobling nødvendig", "components.RequestModal.SearchByNameModal.nosummary": "Fant ingen sammendrag.", "components.RequestModal.AdvancedRequester.rootfolder": "Grunnmappe", "components.RequestModal.AdvancedRequester.requestas": "Forespør som", @@ -336,7 +324,7 @@ "components.PlexLoginButton.signingin": "Logger inn…", "components.PersonDetails.lifespan": "{birthdate} – {deathdate}", "components.PersonDetails.crewmember": "Crew", - "components.PersonDetails.birthdate": "Født [birthdate}", + "components.PersonDetails.birthdate": "Født {birthdate}", "components.PersonDetails.alsoknownas": "Også kjent som: {names}", "components.PermissionEdit.voteDescription": "Gi tilgang til å stemme på forespørsler (stemming er foreløpig ikke implementert).", "components.PermissionEdit.vote": "Stem", @@ -396,7 +384,6 @@ "components.Login.forgotpassword": "Glemt passord?", "components.Login.email": "E-postadresse", "components.AppDataWarning.dockerVolumeMissingDescription": "Volum Mount {appDataPath} er ikke konfigurert korrekt. All data vil slettes når containeren stoppes eller startes på nytt.", - "components.AppDataWarning.dockerVolumeMissing": "Docker Volum Mount Mangler", "i18n.requested": "Forespurt", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "E-postvarsler for Media forespurt, Media automatisk godkjent og Media feilet blir sendt til alle brukere med Administrer forespørsler tilgang.", "components.RequestModal.requestedited": "Redigerte forespørsel for {title}.", @@ -440,8 +427,6 @@ "i18n.experimental": "Eksperimentelt", "components.Settings.hideAvailable": "Skjul tilgjengelig media", "components.Settings.trustProxy": "Aktiver Proxy-støtte", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Brukerkontoen din har foreløpig ikke et passord for {applicationTitle}. Konfigurer et passord for å kunne bruke denne kontoen til å logge inn som en \"lokal bruker\" med e-postadressen din.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Denne brukerkontoen har foreløpig ikke et passord for {applicationTitle}. Konfigurer et passord for å kunne bruke denne kontoen til å logge inn som en \"lokal bruker.\"", "components.Settings.validationApplicationTitle": "Du må oppgi en applikasjonstittel", "components.Settings.applicationTitle": "Applikasjonstittel", "i18n.movie": "Film", @@ -477,7 +462,6 @@ "components.Settings.SettingsAbout.Releases.viewongithub": "Vis på GitHub", "components.Settings.SettingsAbout.Releases.viewchangelog": "Vis endringslogg", "components.Settings.SettingsAbout.Releases.versionChangelog": "Endringslogg", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Utviklerversjon", "components.Settings.SettingsAbout.Releases.releases": "Utgivelser", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Utgivelsesdata er for øyeblikket utilgjengelig.", "components.Settings.SettingsAbout.Releases.latestversion": "Nyeste", @@ -503,20 +487,15 @@ "components.Settings.Notifications.senderName": "Avsendernavn", "components.Settings.Notifications.sendSilentlyTip": "Send varsler uten lyd", "components.Settings.Notifications.sendSilently": "Send lydløst", - "components.Settings.Notifications.pgpPrivateKey": "PGP Privat Nøkkel", - "components.Settings.Notifications.pgpPassword": "PGP Passord", - "components.Settings.Notifications.notificationtypes": "Varseltyper", + "components.Settings.Notifications.pgpPrivateKey": "Privat PGP-nøkkel", + "components.Settings.Notifications.pgpPassword": "PGP-passord", "components.Settings.Notifications.chatId": "Chat ID", "components.Settings.Notifications.NotificationsWebhook.testsent": "Testvarsel sendt!", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Varseltyper", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Aktiver Agent", "components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "Du må oppgi en gyldig URL", "components.Settings.Notifications.NotificationsSlack.testsent": "Testvarsel sendt!", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Konfigurerer Slack-varsler", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Varseltyper", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Aktiver Agent", "components.Settings.Notifications.NotificationsPushover.testsent": "Testvarsel Sendt!", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Varseltyper", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Aktiver Agent", "components.Settings.Notifications.NotificationsPushover.accessToken": "Applikasjon/API-nøkkel", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Du må oppgi en tilgangsnøkkel", @@ -561,5 +540,99 @@ "components.Settings.SettingsJobsCache.download-sync": "Nedlastningssynkronisering", "components.Settings.SettingsJobsCache.command": "Kommando", "components.Settings.Notifications.ssldisabletip": "SSL skal være deaktivert når standard TLS-tilkoblinger benyttes (port 587)", - "components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "Du må oppgi en gyldig URL" + "components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "Du må oppgi en gyldig URL", + "components.Settings.scanning": "Synkroniserer…", + "components.Settings.scan": "Synkroniser bibliotek", + "components.Settings.regionTip": "Filtrer innhold basert på region", + "components.Settings.plex": "Plex", + "components.Settings.notifications": "Varsler", + "components.Settings.general": "Generelle innstillinger", + "components.Settings.enablessl": "Aktiver SSL", + "components.Settings.email": "E-post", + "components.Settings.SonarrModal.validationNameRequired": "Du må oppgi et servernavn", + "components.Settings.SonarrModal.validationLanguageProfileRequired": "Du må velge en språkprofil", + "components.Settings.SonarrModal.toastSonarrTestSuccess": "Koblet til Sonarr!", + "components.Settings.SonarrModal.testFirstTags": "Test tilkobling for å laste inn merker", + "components.Settings.SonarrModal.testFirstRootFolders": "Test tilkobling for å laste inn grunnmapper", + "components.Settings.SonarrModal.testFirstQualityProfiles": "Test tilkobling for å laste inn kvalitetsprofiler", + "components.Settings.SonarrModal.testFirstLanguageProfiles": "Test tilkobling for å laste inn språkprofiler", + "components.Settings.SonarrModal.tags": "Merker", + "components.Settings.SonarrModal.syncEnabled": "Aktiver skanning", + "components.Settings.SonarrModal.selecttags": "Velg merker", + "components.Settings.SonarrModal.selectLanguageProfile": "Velg språkprofil", + "components.Settings.SonarrModal.preventSearch": "Deaktiver auto-søk", + "components.Settings.SonarrModal.notagoptions": "Ingen merker.", + "components.Settings.SonarrModal.loadingrootfolders": "Laster grunnmapper…", + "components.Settings.SonarrModal.loadingprofiles": "Laster kvalitetsprofiler…", + "components.Settings.SonarrModal.loadinglanguageprofiles": "Laster språkprofiler…", + "components.Settings.SonarrModal.loadingTags": "Laster merker…", + "components.Settings.SonarrModal.languageprofile": "Språkprofil", + "components.Settings.SonarrModal.externalUrlPlaceholder": "Ekstern URL som peker mot din Sonarr-server", + "components.Settings.SonarrModal.externalUrl": "Ekstern URL", + "components.Settings.SonarrModal.edit4ksonarr": "Rediger 4K Sonarr-server", + "components.Settings.SonarrModal.default4kserver": "Standard 4K-server", + "components.Settings.SonarrModal.create4ksonarr": "Legg til ny 4K Sonarr-server", + "components.Settings.SonarrModal.animerootfolder": "Anime-grunnmappe", + "components.Settings.SonarrModal.animequalityprofile": "Anime-kvalitetsprofil", + "components.Settings.SonarrModal.animelanguageprofile": "Anime-språkprofil", + "components.Settings.SonarrModal.animeTags": "Anime-merker", + "components.Settings.SettingsLogs.time": "Tidspunkt", + "components.Settings.SettingsLogs.resumeLogs": "Fortsett", + "components.Settings.SettingsLogs.pauseLogs": "Sett på pause", + "components.Settings.SettingsLogs.message": "Rapport", + "components.Settings.SettingsLogs.logsDescription": "Du kan også se disse loggene direkte i stdout, eller i {configDir}/logs/overseerr.log.", + "components.Settings.SettingsLogs.logs": "Logger", + "components.Settings.SettingsLogs.logDetails": "Logg-detaljer", + "components.Settings.SettingsLogs.level": "Alvorlighetsgrad", + "components.Settings.SettingsLogs.label": "Merkelapp", + "components.Settings.SettingsLogs.filterDebug": "Detaljert", + "components.Settings.SettingsLogs.filterError": "Feil", + "components.Settings.SettingsLogs.filterWarn": "Varsel", + "components.Settings.SettingsLogs.filterInfo": "Info", + "components.Settings.RadarrModal.testFirstTags": "Test tilkobling for å laste inn merker", + "components.Settings.RadarrModal.tags": "Merker", + "components.Settings.RadarrModal.selecttags": "Velg merker", + "components.Settings.RadarrModal.notagoptions": "Ingen merker.", + "components.Settings.RadarrModal.loadingTags": "Laster merker…", + "components.Settings.RadarrModal.edit4kradarr": "Rediger 4K Radarr-server", + "components.Settings.RadarrModal.default4kserver": "Standard 4K-server", + "components.Settings.Notifications.telegramsettingssaved": "Lagret Telegram-varselinnstillinger!", + "components.Settings.Notifications.emailsettingssaved": "Lagret e-post-varselinnstillinger!", + "components.Settings.Notifications.discordsettingssaved": "Lagret Discord-varselinnstillinger!", + "components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved": "Lagret Webhook-varselinnstillinger!", + "components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL", + "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Lagret Slack-varselinnstillinger!", + "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Lagret Pushover-varselinnstillinger!", + "components.RequestModal.AdvancedRequester.tags": "Merker", + "components.RequestModal.AdvancedRequester.selecttags": "Velg merker", + "components.RequestModal.AdvancedRequester.notagoptions": "Ingen merker.", + "components.LanguageSelector.originalLanguageDefault": "Alle språk", + "components.LanguageSelector.languageServerDefault": "Standard ({language})", + "i18n.areyousure": "Er du sikker?", + "i18n.failed": "Mislykket", + "components.UserList.usercreatedfailed": "Noe gikk galt ved oppretting av brukeren.", + "components.Settings.toastPlexRefreshFailure": "Kunne ikke hente Plex-serverliste.", + "components.Settings.toastPlexConnectingFailure": "Kunne ikke koble til Plex.", + "components.Settings.SonarrModal.toastSonarrTestFailure": "Kunne ikke koble til Sonarr.", + "components.Settings.Notifications.telegramsettingsfailed": "Kunne ikke lagre Telegram-varselinnstillinger.", + "components.Settings.Notifications.emailsettingsfailed": "Kunne ikke lagre e-postvarselinnstillinger.", + "components.Settings.Notifications.discordsettingsfailed": "Kunne ikke lagre Discord-varselinnstillinger.", + "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Kunne ikke lagre Webhook-varselinnstillinger.", + "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Fikk ikke lagret Slack-varselinnstillinger.", + "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Fikk ikke lagret Pushover-varselinnstillinger.", + "i18n.requesting": "Forespør…", + "i18n.request4k": "Forespør i 4K", + "i18n.request": "Forespør", + "components.UserProfile.totalrequests": "Totalt antall forespørsler", + "components.UserProfile.requestsperdays": "{limit} gjenstår", + "components.UserProfile.recentrequests": "Nylige forespørsler", + "components.UserProfile.norequests": "Ingen forespørsler.", + "components.Settings.noDefaultServer": "Minst én {serverType} server må være definert som standard for at {mediaType}-forespørsler skal kunne bli håndtert.", + "components.RequestModal.pendingapproval": "Forespørselen din avventer godkjenning.", + "components.RequestList.RequestItem.mediaerror": "Media koblet til denne forespørselen er ikke lenger tilgjengelig.", + "components.RequestCard.deleterequest": "Slett forespørsel", + "components.RequestList.RequestItem.deleterequest": "Slett forespørsel", + "components.RequestList.RequestItem.cancelRequest": "Avbryt forespørsel", + "components.RequestCard.mediaerror": "Media koblet til denne forespørselen er ikke lenger tilgjengelig.", + "components.Discover.noRequests": "Ingen forespørsler." } diff --git a/src/i18n/locale/nl.json b/src/i18n/locale/nl.json index 95f8cee7..e3064847 100644 --- a/src/i18n/locale/nl.json +++ b/src/i18n/locale/nl.json @@ -1,7 +1,6 @@ { "components.Discover.discovermovies": "Populaire films", "components.Discover.discovertv": "Populaire series", - "components.Discover.nopending": "Geen verzoeken in behandeling", "components.Discover.popularmovies": "Populaire films", "components.Discover.populartv": "Populaire series", "components.Discover.recentlyAdded": "Recent toegevoegd", @@ -16,12 +15,11 @@ "components.Layout.Sidebar.settings": "Instellingen", "components.Layout.Sidebar.users": "Gebruikers", "components.Layout.UserDropdown.signout": "Uitloggen", - "components.Layout.alphawarning": "Dit is ALPHA software. Functies kunnen kapot of instabiel zijn. Meld eventuele problemen op GitHub!", "components.MovieDetails.budget": "Budget", "components.MovieDetails.cast": "Cast", "components.MovieDetails.manageModalClearMedia": "Wis alle mediadata", "components.MovieDetails.manageModalClearMediaWarning": "* Dit wist alle mediadata voor dit item onherroepelijk, inclusief eventuele verzoeken. Als dit item in je Plex-bibliotheek staat, zal alle media-informatie bij de volgende scan hersteld worden.", - "components.MovieDetails.manageModalNoRequests": "Geen verzoeken", + "components.MovieDetails.manageModalNoRequests": "Geen verzoeken.", "components.MovieDetails.manageModalRequests": "Verzoeken", "components.MovieDetails.manageModalTitle": "Film beheren", "components.MovieDetails.originallanguage": "Originele taal", @@ -59,7 +57,7 @@ "components.Settings.Notifications.enableSsl": "SSL inschakelen", "components.Settings.Notifications.smtpHost": "SMTP-host", "components.Settings.Notifications.smtpPort": "SMTP-poort", - "components.Settings.Notifications.validationSmtpHostRequired": "Je moet een hostnaam of IP-adres opgeven", + "components.Settings.Notifications.validationSmtpHostRequired": "Je moet een geldig(e) hostnaam of IP-adres opgeven", "components.Settings.Notifications.validationSmtpPortRequired": "Je moet een geldig poortnummer opgeven", "components.Settings.Notifications.webhookUrl": "Webhook-URL", "components.Settings.Notifications.webhookUrlPlaceholder": "Serverinstellingen → Integraties → Webhooks", @@ -140,18 +138,15 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "Diensten", "components.Settings.notificationsettings": "Meldingsinstellingen", - "components.Settings.notificationsettingsDescription": "Configureer algemene meldingsinstellingen. De onderstaande opties zijn van toepassing op alle meldingsagenten.", "components.Settings.notrunning": "Niet actief", "components.Settings.plexlibraries": "Plex-bibliotheken", "components.Settings.plexlibrariesDescription": "De bibliotheken die Overseerr scant voor titels. Stel je Plex-verbinding in en sla ze op. Klik daarna op de onderstaande knop als er geen bibliotheken staan.", "components.Settings.plexsettings": "Plex-instellingen", "components.Settings.plexsettingsDescription": "Configureer de instellingen voor je Plex-server. Overseerr scant je Plex-bibliotheken om te zien welke content beschikbaar is.", "components.Settings.port": "Poort", - "components.Settings.radarrSettingsDescription": "Stel hier onder je Radarr-verbinding in. Je kan meerdere Radars-configuraties hebben, maar slechts twee kunnen actief zijn als standaard (één voor standaard HD en één voor 4K). Beheerders kunnen de server aanpassen die gebruikt wordt voor nieuwe verzoeken.", "components.Settings.radarrsettings": "Radarr-instellingen", "components.Settings.servername": "Servernaam", "components.Settings.servernamePlaceholder": "Servernaam Plex", - "components.Settings.sonarrSettingsDescription": "Stel hier onder je Sonarr-verbinding in. Je kan meerdere Sonarr-configuraties hebben, maar slechts twee kunnen actief zijn als standaard (één voor standaard HD en één voor 4K). Beheerders kunnen de server aanpassen die gebruikt wordt voor nieuwe verzoeken.", "components.Settings.sonarrsettings": "Sonarr-instellingen", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Scan starten", @@ -166,7 +161,7 @@ "components.TvDetails.cast": "Cast", "components.TvDetails.manageModalClearMedia": "Wis alle media-data", "components.TvDetails.manageModalClearMediaWarning": "* Dit wist alle mediadata voor dit item onherroepelijk, inclusief eventuele verzoeken. Als dit item in je Plex-bibliotheek staat, zal alle media-informatie bij de volgende scan hersteld worden.", - "components.TvDetails.manageModalNoRequests": "Geen verzoeken", + "components.TvDetails.manageModalNoRequests": "Geen verzoeken.", "components.TvDetails.manageModalRequests": "Verzoeken", "components.TvDetails.manageModalTitle": "Serie beheren", "components.TvDetails.originallanguage": "Originele taal", @@ -213,8 +208,6 @@ "components.Settings.SettingsAbout.overseerrinformation": "Overseerr-informatie", "components.Settings.SettingsAbout.githubdiscussions": "GitHub-discussies", "components.Setup.tip": "Tip", - "components.Settings.nodefaultdescription": "Tenminste één server moet geselecteerd zijn als standaard voordat verzoeken doorkomen bij je diensten.", - "components.Settings.nodefault": "Geen standaardserver", "components.Settings.SonarrModal.testFirstRootFolders": "Test verbinding om hoofdmappen te laden", "components.Settings.SonarrModal.testFirstQualityProfiles": "Test verbinding om kwaliteitsprofielen te laden", "components.Settings.SonarrModal.loadingrootfolders": "Bezig met laden van hoofdmappen…", @@ -228,7 +221,7 @@ "components.Settings.SettingsAbout.Releases.releasedataMissing": "Versiegegevens niet beschikbaar. Is GitHub offline?", "components.Settings.SettingsAbout.Releases.latestversion": "Nieuwste", "components.Settings.SettingsAbout.Releases.currentversion": "Huidige versie", - "components.Settings.Notifications.testsent": "Testmelding verzonden!", + "components.Settings.Notifications.testsent": "Testmelding Telegram verzonden!", "components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studio's}}", "components.CollectionDetails.overview": "Overzicht", "components.CollectionDetails.numberofmovies": "{count} films", @@ -246,7 +239,7 @@ "components.UserList.importfromplexerror": "Er is iets misgegaan bij het importeren van gebruikers uit Plex.", "components.UserList.importfromplex": "Gebruikers importeren uit Plex", "components.UserList.deleteuser": "Gebruiker verwijderen", - "components.UserList.deleteconfirm": "Weet je zeker dat je deze gebruiker wilt verwijderen? Alle bestaande aanvraaggegevens van deze gebruiker zullen worden verwijderd.", + "components.UserList.deleteconfirm": "Weet je zeker dat je deze gebruiker wilt verwijderen? Al hun bestaande aanvraaggegevens zullen worden verwijderd.", "components.TvDetails.watchtrailer": "Trailer bekijken", "components.TvDetails.viewfullcrew": "Volledige crew bekijken", "components.TvDetails.showtype": "Type serie", @@ -269,20 +262,17 @@ "components.Settings.SettingsAbout.Releases.viewongithub": "Bekijken op GitHub", "components.Settings.SettingsAbout.Releases.viewchangelog": "Changelog bekijken", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "De laatste wijzigingen aan de tak develop van Overseerr worden hieronder niet getoond. Zie de commit-geschiedenis voor deze tak op GitHub voor details.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Ontwikkelingsversie", "components.Settings.Notifications.validationChatIdRequired": "Je moet een geldige chat-ID opgeven", "components.Settings.Notifications.validationBotAPIRequired": "Je moet een bot-verificatietoken opgeven", "components.Settings.Notifications.telegramsettingssaved": "Instellingen Telegrammeldingen met succes opgeslagen!", "components.Settings.Notifications.telegramsettingsfailed": "De instellingen voor Telegrammeldingen konden niet opgeslagen worden.", "components.Settings.Notifications.ssldisabletip": "SSL moet worden uitgeschakeld op standaard TLS-verbindingen (poort 587)", "components.Settings.Notifications.senderName": "Naam afzender", - "components.Settings.Notifications.notificationtypes": "Meldingtypes", "components.Settings.Notifications.chatId": "Chat-ID", "components.Settings.Notifications.botAPI": "Bot-authenticatietoken", "components.Settings.Notifications.allowselfsigned": "Self-signed certificaten toestaan", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook-URL", - "components.Settings.Notifications.NotificationsSlack.testsent": "Testmelding verzonden!", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Meldingtypes", + "components.Settings.Notifications.NotificationsSlack.testsent": "Testmelding Slack verzonden!", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Agent inschakelen", "components.RequestList.RequestItem.failedretry": "Er ging opnieuw iets mis tijdens het aanvragen.", "components.PersonDetails.crewmember": "Crew", @@ -298,17 +288,14 @@ "components.Settings.SettingsAbout.Releases.versionChangelog": "Changelog", "components.Settings.SettingsAbout.Releases.releases": "Versies", "components.Settings.Notifications.settinguptelegramDescription": "Om Telegrammeldingen in te stellen, moet je een bot aanmaken en de API-sleutel van de bot gebruiken. Je hebt ook de Chat ID nodig van de chat waarin je meldingen wilt sturen. Dit kun je vinden door @get_id_bot aan de chat toe te voegen en het commando /my_id uit te voeren.", - "components.Settings.Notifications.settinguptelegram": "Telegrammeldingen instellen", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Instellingen voor Slack-meldingen met succes opgeslagen!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Instellingen voor Slack-meldingen konden niet opgeslagen worden.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Om Slack-meldingen in te stellen moet je een Incoming Webhook integratie gebruiken en de webhook-URL hieronder ingeven.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Slack-meldingen instellen", "components.NotificationTypeSelector.mediarequestedDescription": "Een melding sturen wanneer media is aangevraagd en goedkeuring vereist.", "components.NotificationTypeSelector.mediafailedDescription": "Een melding sturen wanneer aangevraagde media niet toegevoegd kan worden aan Radarr of Sonarr.", "components.TvDetails.TvCrew.fullseriescrew": "Volledige crew van de serie", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Instellingen voor Pushover-meldingen met succes opgeslagen!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Instellingen voor Pushover-meldingen konden niet opgeslagen worden.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Meldingtypes", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Agent inschakelen", "components.Settings.Notifications.NotificationsPushover.accessToken": "Toepassings-/API-token", "components.RequestList.sortModified": "Laatst gewijzigd", @@ -316,10 +303,9 @@ "components.RequestList.showallrequests": "Toon alle verzoeken", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Je moet een geldige gebruikerssleutel opgeven", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Je moet een geldig toepassingstoken opgeven", - "components.Settings.Notifications.NotificationsPushover.userToken": "Gebruikerssleutel", - "components.Settings.Notifications.NotificationsPushover.testsent": "Testmelding verzonden!", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Om Pushover in te stellen, moet je een applicatie registreren en de API-token hieronder invoeren. (Je kunt een van onze officiële pictogrammen op GitHub gebruiken.) Je hebt ook je gebruikerssleutel nodig.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Pushover-meldingen instellen", + "components.Settings.Notifications.NotificationsPushover.userToken": "Gebruikers- of groepssleutel", + "components.Settings.Notifications.NotificationsPushover.testsent": "Testmelding Pushover verzonden!", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Om Pushover in te stellen, moet je een applicatie registreren en de API-token hieronder invoeren. (Je kan een van de officiële Overseerr-pictogrammen op GitHub gebruiken.)", "i18n.request": "Aanvragen", "components.RequestButton.requestmore4k": "Meer 4K aanvragen", "components.RequestButton.approverequests": "{requestCount} {requestCount, plural, one {verzoek} other {verzoeken}} goedkeuren", @@ -331,11 +317,10 @@ "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Instellingen voor webhook-meldingen konden niet opgeslagen worden.", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "Webhook-URL", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "Je moet een geldige JSON-payload opgeven", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Testmelding verzonden!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Testmelding webhook verzonden!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Hulp met sjabloonvariabelen", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON-payload met succes teruggezet!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Terugzetten naar standaard", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Meldingtypes", "components.Settings.Notifications.NotificationsWebhook.customJson": "JSON-payload", "components.Settings.Notifications.NotificationsWebhook.authheader": "Autorisatie-header", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Agent inschakelen", @@ -357,8 +342,7 @@ "components.UserList.creating": "Bezig met aanmaken…", "components.UserList.validationpasswordminchars": "Wachtwoord is te kort; moet minimaal 8 tekens bevatten", "components.UserList.usercreatedsuccess": "Gebruiker met succes aangemaakt!", - "components.UserList.passwordinfodescription": "Instellingen voor e-mailmeldingen moeten geconfigureerd en ingeschakeld worden om wachtwoorden automatisch te genereren.", - "components.UserList.passwordinfo": "Wachtwoordinformatie", + "components.UserList.passwordinfodescription": "E-mailmeldingen moeten ingeschakeld worden om wachtwoorden automatisch te genereren.", "components.UserList.password": "Wachtwoord", "components.UserList.localuser": "Lokale gebruiker", "components.UserList.email": "E-mailadres", @@ -390,17 +374,12 @@ "components.Settings.hideAvailable": "Beschikbare media verbergen", "components.RequestModal.requesterror": "Er ging iets mis bij het aanvragen.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "We konden je verzoek niet automatisch matchen. Selecteer de juiste match uit de onderstaande lijst.", - "components.RequestModal.SearchByNameModal.notvdbid": "Manuele match vereist", "components.RequestModal.SearchByNameModal.nosummary": "Er is geen samenvatting voor deze titel gevonden.", "components.Login.signinwithplex": "Plex-account gebruiken", "components.Login.signinheader": "Log in om verder te gaan", "components.Login.signingin": "Bezig met inloggen…", "components.Login.signin": "Inloggen", - "components.Settings.notificationsettingssaved": "Meldingsinstellingen met succes opgeslagen!", - "components.Settings.notificationsettingsfailed": "Meldingsinstellingen kunnen niet opgeslagen worden.", - "components.Settings.notificationAgentsSettings": "Meldingsagenten", - "components.Settings.notificationAgentSettingsDescription": "Kies de soorten meldingen die je wilt verzenden en welke meldingsagenten je wilt gebruiken.", - "components.Settings.enablenotifications": "Meldingen inschakelen", + "components.Settings.notificationAgentSettingsDescription": "Meldingsagenten configureren en inschakelen.", "components.PlexLoginButton.signinwithplex": "Inloggen", "components.PlexLoginButton.signingin": "Bezig met inloggen…", "components.PermissionEdit.advancedrequest": "Geavanceerde aanvragen", @@ -414,8 +393,7 @@ "components.Settings.toastPlexConnectingSuccess": "Succesvol verbonden met Plex-server!", "components.Settings.toastPlexConnectingFailure": "Kan geen verbinding maken met Plex.", "components.Settings.timeout": "Time-out", - "components.Settings.settingUpPlexDescription": "Om Plex in te stellen, kan je jouw gegevens handmatig invoeren of een server selecteren die is opgehaald van plex.tv. Druk op de knop rechts van de vervolgkeuzelijst om de verbinding te checken en beschikbare servers op te halen.", - "components.Settings.settingUpPlex": "Plex instellen", + "components.Settings.settingUpPlexDescription": "Om Plex in te stellen, kan je jouw gegevens handmatig invoeren of een server selecteren die is opgehaald van plex.tv. Druk op de knop rechts van de vervolgkeuzelijst om de lijst van beschikbare servers op te halen.", "components.Settings.serverpresetRefreshing": "Bezig met servers ophalen…", "components.Settings.serverpresetPlaceholder": "Plex-server", "components.Settings.serverpresetManualMessage": "Handmatige configuratie", @@ -510,7 +488,6 @@ "components.Discover.discover": "Ontdekken", "components.Settings.validationApplicationTitle": "Je moet een toepassingstitel opgeven", "components.AppDataWarning.dockerVolumeMissingDescription": "De volumekoppeling {appDataPath} was niet correct geconfigureerd. Alle gegevens zullen worden gewist wanneer de container wordt gestopt of opnieuw wordt gestart.", - "components.AppDataWarning.dockerVolumeMissing": "Docker-volumekoppeling ontbreekt", "components.Settings.validationApplicationUrlTrailingSlash": "URL mag niet eindigen op een schuine streep", "components.Settings.validationApplicationUrl": "Je moet een geldige URL opgeven", "components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL mag niet eindigen op een schuine streep", @@ -562,11 +539,9 @@ "components.PermissionEdit.autoapprove4k": "Automatische goedkeuring 4K", "components.UserProfile.recentrequests": "Recente verzoeken", "components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "Algemene instellingen", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Dit gebruikersaccount heeft momenteel geen specifiek wachtwoord voor {applicationTitle}. Configureer hieronder een wachtwoord zodat dit account zich kan aanmelden als 'lokale gebruiker'.", "components.UserProfile.UserSettings.menuNotifications": "Meldingen", "components.UserProfile.UserSettings.menuGeneralSettings": "Algemeen", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Meldingen inschakelen", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord-ID", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Gebruikers-ID", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "Wachtwoord is te kort; moet minimaal 8 tekens bevatten", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "Je moet een nieuw wachtwoord opgeven", "components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "Je moet jouw huidige wachtwoord opgeven", @@ -576,7 +551,6 @@ "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Er ging iets mis bij het opslaan van het wachtwoord.", "components.UserProfile.UserSettings.UserPasswordChange.password": "Wachtwoord", "components.UserProfile.UserSettings.menuChangePass": "Wachtwoord", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Geen wachtwoord ingesteld", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nieuw wachtwoord", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Huidig wachtwoord", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Wachtwoord bevestigen", @@ -597,18 +571,16 @@ "components.UserList.edituser": "Gebruikersrechten bewerken", "components.UserProfile.ProfileHeader.settings": "Instellingen bewerken", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Je moet een toegangstoken opgeven", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Testmelding verzonden!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Om Pushbullet-meldingen te configureren, moet u een toegangstoken aanmaken en hieronder invoeren.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Pushbullet-meldingen instellen", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Testmelding Pushbullet verzonden!", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Om Pushbullet-meldingen te configureren, moet u een toegangstoken aanmaken.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Instellingen voor Pushbullet-meldingen met succes opgeslagen!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Instellingen voor Pushbullet-meldingen konden niet opgeslagen worden.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Meldingtypes", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Agent inschakelen", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Toegangstoken", "components.Layout.UserDropdown.settings": "Instellingen", "components.Layout.UserDropdown.myprofile": "Profiel", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Je moet een geldige Discord-gebruikers-ID opgeven", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "Het ID-nummer van je Discord-gebruikersaccount", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Je moet een geldige gebruikers-ID opgeven", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "Het ID-nummer van je gebruikersaccount", "components.CollectionDetails.requestswillbecreated4k": "De volgende titels zullen in 4K aangevraagd worden:", "components.CollectionDetails.requestcollection4k": "Collectie in 4K aanvragen", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Inhoud filteren op regionale beschikbaarheid", @@ -622,7 +594,6 @@ "components.Settings.originallanguage": "Taal van Ontdekken", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "E-mailmeldingen Media aangevraagd, Media automatisch goedgekeurd en Media mislukt worden verzonden naar alle gebruikers met de machtiging Verzoeken beheren.", "components.Settings.email": "E-mail", - "components.Settings.Notifications.emailNotificationTypesAlert": "Ontvangers van e-mailmeldingen", "components.RegionSelector.regionDefault": "Alle regio’s", "components.Discover.upcomingtv": "Verwachte series", "components.RegionSelector.regionServerDefault": "Standaard ({region})", @@ -639,12 +610,11 @@ "components.Settings.SettingsJobsCache.download-sync": "Synchroniseer downloads", "components.TvDetails.seasons": "{seasonCount, plural, one {# seizoen} other {# seizoenen}}", "i18n.loading": "Bezig met laden…", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Je moet een geldige chat-ID van Telegram opgeven", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Je moet een geldige chat-ID opgeven", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Een chat starten, @get_id_bot toevoegen en de opdracht /my_id geven", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "@get_id_bot aan de chat toevoegen", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram chat-ID", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat-ID", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Meldingen versturen zonder geluid", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Telegram-berichten stil versturen", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Stil versturen", "components.Settings.Notifications.botUsername": "Gebruikersnaam bot", "components.Discover.DiscoverTvGenre.genreSeries": "{genre} series", "components.Discover.DiscoverStudio.studioMovies": "Films van {studio}", @@ -680,15 +650,13 @@ "components.NotificationTypeSelector.mediaAutoApproved": "Media automatisch goedgekeurd", "components.UserProfile.UserSettings.unauthorizedDescription": "Je hebt geen toestemming om de instellingen van deze gebruiker te wijzigen.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "Je kan je eigen machtigingen niet wijzigen.", - "components.UserProfile.norequests": "Geen verzoeken", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "E-mailberichten versleutelen", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "Publieke sleutel PGP", + "components.UserProfile.norequests": "Geen verzoeken.", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minuten", "components.TvDetails.episodeRuntime": "Afleveringsduur", - "components.Settings.Notifications.pgpPrivateKeyTip": "Versleutelde e-mailberichten ondertekenen (PGP-wachtwoord is ook vereist)", - "components.Settings.Notifications.pgpPrivateKey": "Privésleutel PGP", - "components.Settings.Notifications.pgpPasswordTip": "Versleutelde e-mailberichten ondertekenen (PGP-privésleutel is ook vereist)", - "components.Settings.Notifications.pgpPassword": "Wachtwoord PGP", + "components.Settings.Notifications.pgpPrivateKeyTip": "Versleutelde e-mailberichten ondertekenen met OpenPGP", + "components.Settings.Notifications.pgpPrivateKey": "Privésleutel PGP", + "components.Settings.Notifications.pgpPasswordTip": "Versleutelde e-mailberichten ondertekenen met OpenPGP", + "components.Settings.Notifications.pgpPassword": "Wachtwoord PGP", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.Discover.TvGenreSlider.tvgenres": "Seriegenres", "components.Discover.MovieGenreSlider.moviegenres": "Filmgenres", @@ -718,7 +686,6 @@ "i18n.usersettings": "Gebruikersinstellingen", "i18n.settings": "Instellingen", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Er ging iets mis bij het opslaan van het wachtwoord. Is je huidige wachtwoord correct ingevoerd?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Jouw account heeft momenteel geen wachtwoord specifiek voor {applicationTitle}. Configureer hieronder een wachtwoord om in te kunnen loggen als een \"lokale gebruiker\" met je e-mailadres.", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Meldingen", "components.UserProfile.UserSettings.UserGeneralSettings.general": "Algemeen", "components.Settings.services": "Diensten", @@ -756,7 +723,7 @@ "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {seizoen} other {seizoenen}}", "components.RequestModal.QuotaDisplay.season": "seizoen", "components.RequestModal.QuotaDisplay.requiredquota": "Je moet nog minstens {seasons} {seasons, plural, one {seizoensverzoek} other {seizoensverzoek}} over hebben om deze serie aan te vragen.", - "components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {Geen} other {#}} {type} {remaining, plural, one {verzoek} other {verzoeken}} resterend", + "components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {Geen} other {#}} {type}{remaining, plural, one {verzoek} other {verzoeken}} resterend", "components.RequestModal.QuotaDisplay.quotaLinkUser": "Je kan een overzicht van de aanvraaglimieten van deze gebruiker bekijken op hun profielpagina.", "components.RequestModal.QuotaDisplay.quotaLink": "Je kan een overzicht van je aanvraaglimieten bekijken op jouw profielpagina.", "components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Onvoldoende seizoensverzoeken over", @@ -768,7 +735,6 @@ "components.QuotaSelector.tvRequestLimit": "{quotaLimit} seizoen(en) per {quotaDays} dag(en)", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} film(s) per {quotaDays} dag(en)", "i18n.view": "Bekijken", - "i18n.unauthorized": "Onbevoegd", "i18n.tvshow": "Serie", "i18n.testing": "Bezig met testen…", "i18n.test": "Test", @@ -792,5 +758,62 @@ "components.TvDetails.originaltitle": "Originele titel", "components.MovieDetails.originaltitle": "Originele titel", "components.LanguageSelector.originalLanguageDefault": "Alle talen", - "components.LanguageSelector.languageServerDefault": "Standaard ({language})" + "components.LanguageSelector.languageServerDefault": "Standaard ({language})", + "components.Settings.SonarrModal.testFirstTags": "Test de verbinding om labels te laden", + "components.Settings.SonarrModal.tags": "Labels", + "components.Settings.SonarrModal.selecttags": "Labels selecteren", + "components.Settings.SonarrModal.notagoptions": "Geen labels.", + "components.Settings.SonarrModal.loadingTags": "Labels laden…", + "components.Settings.SonarrModal.edit4ksonarr": "4K Sonarr-server bewerken", + "components.Settings.SonarrModal.default4kserver": "Standaard 4K-server", + "components.Settings.SonarrModal.create4ksonarr": "Nieuwe 4K Sonarr-server toevoegen", + "components.Settings.SonarrModal.animeTags": "Animelabels", + "components.Settings.RadarrModal.testFirstTags": "Test de verbinding om labels te laden", + "components.Settings.RadarrModal.tags": "Labels", + "components.Settings.RadarrModal.selecttags": "Labels selecteren", + "components.Settings.RadarrModal.notagoptions": "Geen labels.", + "components.Settings.RadarrModal.edit4kradarr": "4K Radarr-server bewerken", + "components.Settings.RadarrModal.default4kserver": "Standaard 4K-server", + "components.Settings.RadarrModal.create4kradarr": "Nieuwe 4K Radarr-server toevoegen", + "components.RequestModal.AdvancedRequester.tags": "Labels", + "components.RequestModal.AdvancedRequester.selecttags": "Labels selecteren", + "components.RequestModal.AdvancedRequester.notagoptions": "Geen labels.", + "components.Settings.RadarrModal.loadingTags": "Labels laden…", + "components.RequestList.RequestItem.mediaerror": "De gekoppelde titel voor dit verzoek is niet meer beschikbaar.", + "components.RequestList.RequestItem.deleterequest": "Verzoek verwijderen", + "components.RequestCard.mediaerror": "De gekoppelde titel voor dit verzoek is niet meer beschikbaar.", + "components.RequestCard.deleterequest": "Verzoek verwijderen", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Je moet een geldige openbare PGP-sleutel opgeven", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Instellingen Telegrammeldingen met succes opgeslagen!", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "De instellingen voor Telegrammeldingen konden niet opgeslagen worden.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "E-mailberichten versleutelen met OpenPGP", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Openbare PGP-sleutel", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Meldingen inschakelen", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Meldingen inschakelen", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Vermeldingen inschakelen", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Instellingen voor e-mailmeldingen met succes opgeslagen!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Instellingen voor e-mailmeldingen konden niet opgeslagen worden.", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "E-mail", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Instellingen voor Discord-meldingen zijn met succes opgeslagen!", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Instellingen voor Discord-meldingen konden niet opgeslagen worden.", + "components.Settings.Notifications.validationPgpPrivateKey": "Je moet een geldige PGP-privésleutel opgeven als een PGP-wachtwoord ingevoerd is", + "components.Settings.Notifications.validationPgpPassword": "Je moet een PGP-wachtwoord opgeven als een PGP-privésleutel ingevoerd is", + "components.Settings.Notifications.botUsernameTip": "Sta gebruikers toe om een chat met de bot te starten en hun eigen persoonlijke meldingen te configureren", + "components.RequestModal.pendingapproval": "Je verzoek is in afwachting van goedkeuring.", + "components.RequestList.RequestItem.cancelRequest": "Verzoek annuleren", + "components.NotificationTypeSelector.notificationTypes": "Meldingtypes", + "components.Discover.noRequests": "Geen verzoeken.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Er is voor jouw account momenteel geen wachtwoord ingesteld. Configureer hieronder een wachtwoord om in te kunnen loggen als een \"lokale gebruiker\" met uw e-mailadres.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Voor deze gebruikersaccount is er momenteel geen wachtwoord ingesteld. Configureer hieronder een wachtwoord om ervoor te zorgen dat dit account zich kan aanmelden als een \"lokale gebruiker\".", + "components.Settings.serviceSettingsDescription": "Configureer je {serverType} server(s) hieronder. Je kunt meerdere {serverType} servers verbinden, maar slechts twee ervan kunnen als standaard worden gemarkeerd (één niet-4K en één 4K). Beheerders kunnen vóór de goedkeuring de server die gebruikt wordt om nieuwe aanvragen te verwerken aanpassen.", + "components.Settings.noDefaultServer": "Ten minste één {serverType} server moet als standaard worden gemarkeerd om {mediaType}verzoeken te kunnen verwerken.", + "components.Settings.noDefaultNon4kServer": "Als je slechts één enkele {serverType} server hebt voor zowel niet-4K als 4K-inhoud (of als je alleen 4K-inhoud downloadt), dan moet je {serverType} server NIET aangeduid worden als een 4K-server.", + "components.Settings.mediaTypeSeries": "serie", + "components.Settings.mediaTypeMovie": "film", + "components.Settings.SettingsAbout.uptodate": "Bijgewerkt", + "components.Settings.SettingsAbout.outofdate": "Verouderd", + "components.Layout.VersionStatus.streamdevelop": "Overseerr ontwikkel", + "components.Layout.VersionStatus.streamstable": "Overseerr stabiel", + "components.Layout.VersionStatus.outofdate": "Verouderd", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} achter" } diff --git a/src/i18n/locale/pt_BR.json b/src/i18n/locale/pt_BR.json index e5f55134..c0c4ecf4 100644 --- a/src/i18n/locale/pt_BR.json +++ b/src/i18n/locale/pt_BR.json @@ -14,13 +14,12 @@ "components.MovieDetails.originallanguage": "Língua Original", "components.MovieDetails.manageModalTitle": "Gerenciar Filme", "components.MovieDetails.manageModalRequests": "Solicitações", - "components.MovieDetails.manageModalNoRequests": "Nenhuma Solicitação", + "components.MovieDetails.manageModalNoRequests": "Nenhuma solicitação.", "components.MovieDetails.manageModalClearMediaWarning": "* Isso irá remover em definitivo todos dados deste filme, incluindo todas solicitações. Se este item existir em sua biblioteca do Plex, os dados de mídia serão recriados no próximo escaneamento.", "components.MovieDetails.manageModalClearMedia": "Limpar Todos Dados de Mídia", "components.MovieDetails.cast": "Elenco", "components.MovieDetails.budget": "Orçamento", "components.MovieDetails.MovieCast.fullcast": "Elenco Completo", - "components.Layout.alphawarning": "Essa é uma versão Alpha. Algumas funcionalidades podem ser instáveis ou não funcionarem. Por favor reporte qualquer problema no GitHub!", "components.Layout.UserDropdown.signout": "Sair", "components.Layout.Sidebar.users": "Usuários", "components.Layout.Sidebar.settings": "Configurações", @@ -35,16 +34,12 @@ "components.Discover.recentlyAdded": "Adicionado Recentemente", "components.Discover.populartv": "Séries Populares", "components.Discover.popularmovies": "Filmes Populares", - "components.Discover.nopending": "Nenhuma Solicitação Pendente", "components.Discover.discovertv": "Séries Populares", "components.Discover.discovermovies": "Filmes Populares", "components.Settings.plexlibraries": "Bibliotecas do Plex", "components.Settings.notrunning": "Parado", - "components.Settings.notificationsettingsDescription": "Configuração global de notificações. As configurações abaixo afetam todos agentes de notificação.", "components.RequestModal.season": "Temporada", "components.Settings.notificationsettings": "Configurações de Notificação", - "components.Settings.nodefaultdescription": "Pelo menos um servidor deve ser selecionado como padrão antes que qualquer solicitação chegue aos seus serviços.", - "components.Settings.nodefault": "Nenhum Servidor Padrão", "components.Settings.menuServices": "Serviços", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuNotifications": "Notificações", @@ -145,7 +140,7 @@ "components.Settings.Notifications.webhookUrlPlaceholder": "Config. do Servidor -> Integrações -> Webhooks", "components.Settings.Notifications.webhookUrl": "URL de Webhook", "components.Settings.Notifications.validationSmtpPortRequired": "Você deve prover uma porta válida", - "components.Settings.Notifications.validationSmtpHostRequired": "Você deve prover um nome ou IP de servidor", + "components.Settings.Notifications.validationSmtpHostRequired": "Você deve prover um nome válido ou IP de servidor", "components.Settings.Notifications.smtpPort": "Porta SMTP", "components.Settings.Notifications.smtpHost": "Servidor SMTP", "components.Settings.Notifications.enableSsl": "Habilitar SSL", @@ -197,7 +192,6 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Ver Mudanças", "components.Settings.SettingsAbout.Releases.versionChangelog": "Mudanças Nessa Versão", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "As últimas mudanças na versão em desenvolvimento não serão exibidas abaixo. Por favor acesse o histórico de mudanças no GitHub para detalhes.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Versão em Desenvolvimento", "components.Settings.SettingsAbout.Releases.releases": "Versões", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Informações de versão indisponíveis. O GitHub está indisponível?", "components.Settings.SettingsAbout.Releases.latestversion": "Última Versão", @@ -209,7 +203,7 @@ "components.TvDetails.network": "{networkCount, plural, one {Emissora} other {Emissoras}}", "components.TvDetails.manageModalTitle": "Gerenciar Série", "components.TvDetails.manageModalRequests": "Solicitações", - "components.TvDetails.manageModalNoRequests": "Nenhuma Solicitação", + "components.TvDetails.manageModalNoRequests": "Nenhuma solicitação.", "components.TvDetails.manageModalClearMedia": "Limpar Todos Dados de Mídia", "components.TvDetails.cast": "Elenco", "components.TvDetails.anime": "Animes", @@ -244,15 +238,13 @@ "components.UserList.plexuser": "Usuário Plex", "components.UserList.lastupdated": "Última Atualização", "components.UserList.deleteuser": "Deletar Usuário", - "components.UserList.deleteconfirm": "Tem certeza que deseja deletar esse usuário? Todas informações de solicitações feitas por esse usuário serão removidas.", + "components.UserList.deleteconfirm": "Tem certeza que deseja deletar esse usuário? Todas informações de solicitações feitas por esse usuário serão permanentemente removidas.", "components.UserList.created": "Criado", "components.UserList.admin": "Administrador", "components.TvDetails.similar": "Séries Semelhantes", "components.TvDetails.showtype": "Tipo de Série", "components.TvDetails.manageModalClearMediaWarning": "* Isso irá remover em definitivo todos dados desta série, incluindo todas solicitações. Se este item existir em sua biblioteca do Plex, as informações de mídia serão recriadas no próximo escaneamento.", - "components.Settings.sonarrSettingsDescription": "Configure abaixo sua conexão com Sonarr. Você pode criar conexões com múltiplos servidores Sonarr, mas apenas dois por vez como padrão (um para padrão HD, e outro para 4K). Administradores podem alterar o servidor que será usado para novas solicitações.", - "components.Settings.radarrSettingsDescription": "Configure abaixo sua conexão com Radarr. Você pode criar conexões com múltiplos servidores Radarr, mas apenas dois por vez como padrão (um para padrão HD, e outro para 4K). Administradores podem alterar o servidor que será usado para novas solicitações.", - "components.Settings.Notifications.testsent": "Notificação de teste enviada!", + "components.Settings.Notifications.testsent": "Notificação Telegram de teste enviada!", "components.RequestModal.requestseasons": "Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}", "components.TvDetails.viewfullcrew": "Ver Toda Equipe Técnica", "components.TvDetails.TvCrew.fullseriescrew": "Equipe Técnica Completa da Série", @@ -262,7 +254,6 @@ "components.UserList.importfromplexerror": "Algo deu errado ao importar usuários do Plex.", "components.UserList.importfromplex": "Importar Usuários do Plex", "components.UserList.importedfromplex": "{userCount, plural, one {# novo usuário} other {# novos usuários}} importados do Plex com sucesso!", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Configurando Notificações Via Slack", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Habilitar Agente", "components.RequestList.RequestItem.failedretry": "Algo deu errado ao retentar fazer a solicitação.", "components.MovieDetails.watchtrailer": "Assistir Trailer", @@ -283,12 +274,11 @@ "components.Settings.Notifications.telegramsettingsfailed": "Falha ao salvar configurações de notificação via Telegram.", "components.Settings.Notifications.ssldisabletip": "SSL deve ser desabilitado em conexões TLS padrão (porta 587)", "components.Settings.Notifications.settinguptelegramDescription": "Para configurar notificações via Telegram, você precisará criar um bot e obter a chave de API do mesmo. Além disso, você irá precisar do ID de Chat de onde você deseja que o bot envie as notificações. Você pode obter o ID de Chat adicionando @get_id_bot ao chat ou grupo ao qual você deseja obter o ID e executar o comando /my_id.", - "components.Settings.Notifications.settinguptelegram": "Configurando Notificações Via Telegram", "components.Settings.Notifications.chatId": "ID de Chat", "components.Settings.Notifications.botAPI": "Token de Autenticação do Bot", "components.Settings.Notifications.allowselfsigned": "Permitir certificados auto-assinados", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL de Webhook", - "components.Settings.Notifications.NotificationsSlack.testsent": "Notificação de teste enviada!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Notificação Slack de teste enviada!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Configurações de notificação via Slack salvas com sucesso!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Falha ao salvar configurações de notificação via Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Para usar notificações via Slack você irá precisar criar uma integração Webhook de entrada e usar no campo abaixo a URL gerada.", @@ -296,8 +286,6 @@ "components.StatusChacker.newversionDescription": "Overseer foi atualizado! Por favor clique no botão abaixo para recarregar a página.", "components.StatusChacker.newversionavailable": "Atualização da Aplicação", "components.Settings.SettingsAbout.documentation": "Documentação", - "components.Settings.Notifications.notificationtypes": "Tipos de Notificação", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Tipos de Notificação", "components.NotificationTypeSelector.mediarequestedDescription": "Envia uma notificação quando um nova mídia é solicitada e requer aprovação.", "components.NotificationTypeSelector.mediaavailable": "Mídia Disponível", "components.NotificationTypeSelector.mediaapproved": "Mídia Aprovada", @@ -309,13 +297,11 @@ "i18n.request": "Solicitar", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Você deve prover uma chave válida de acesso do usúario", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Você deve prover uma chave válida de acesso", - "components.Settings.Notifications.NotificationsPushover.userToken": "Chave do Usuário", - "components.Settings.Notifications.NotificationsPushover.testsent": "Notificação de teste enviada!", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar notificações via Pushover, você precisará registrar um aplicativo e inserir o token de acesso abaixo. (Você pode user um de nossos ícones oficiais.) Você precisará também sua chave de usuário.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Configurando Notificações Via Pushover", + "components.Settings.Notifications.NotificationsPushover.userToken": "Chave do Usuário ou Grupo", + "components.Settings.Notifications.NotificationsPushover.testsent": "Notificação Pushover de teste enviada!", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar notificações via Pushover, você precisará registrar um aplicativo e inserir o token de acesso abaixo. (Você pode usar um dos ícones oficiais do Overseerr disponíveis no GitHub.)", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Configurações de notificação via Pushover salvas com sucesso!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Falha ao salvar configurações de notificação via Pushover.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Tipos de Notificação", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Habilitar Agente", "components.Settings.Notifications.NotificationsPushover.accessToken": "Token de Acesso", "components.RequestList.sortModified": "Última Mudança", @@ -329,11 +315,10 @@ "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Falha ao salvar configurações de notificação via Webhook.", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "URL de Webhook", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "Você deve prover um conteúdo JSON válido", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Notificação de teste enviada!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Notificação Webhook de teste enviada!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Ajuda Com Modelos de Variáveis", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON restaurado para conteúdo padrão!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Restaurar Padrão", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Tipos de Notificação", "components.Settings.Notifications.NotificationsWebhook.customJson": "Conteúdo JSON", "components.Settings.Notifications.NotificationsWebhook.authheader": "Cabeçalho de Autorização", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Habilitar Agente", @@ -352,8 +337,7 @@ "components.UserList.validationpasswordminchars": "Senha muito curta; necessário ter no mínimo 8 caracteres", "components.UserList.usercreatedsuccess": "Usuário criado com sucesso!", "components.UserList.usercreatedfailed": "Algo deu errado ao criar usuário.", - "components.UserList.passwordinfodescription": "Para usar a geração automática de senhas, é necessário que as configurações de notificação via e-mail estejam ativas.", - "components.UserList.passwordinfo": "Informações de Senha", + "components.UserList.passwordinfodescription": "Habilite notificações via e-mail para permitir a geração automática de senha.", "components.UserList.password": "Senha", "components.UserList.localuser": "Usuário Local", "components.UserList.email": "Endereço de E-mail", @@ -361,7 +345,7 @@ "components.UserList.createuser": "Criar usuário", "components.UserList.createlocaluser": "Criar Usuário Local", "components.UserList.create": "Criar", - "components.UserList.autogeneratepassword": "Gerar senha automaticamente", + "components.UserList.autogeneratepassword": "Gerar Senha Automaticamente", "components.Login.validationpasswordrequired": "Você deve prover uma senha", "components.Login.validationemailrequired": "Você deve prover um e-mail válido", "components.Login.signinwithoverseerr": "Entrar com sua conta {applicationTitle}", @@ -390,7 +374,6 @@ "components.Settings.hideAvailable": "Ocultar Títulos Disponíveis", "components.RequestModal.requesterror": "Algo deu errado ao solicitar mídia.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Não conseguimos correlacionar sua solicitação automaticamente. Por favor selecione a correspondência correta na lista abaixo.", - "components.RequestModal.SearchByNameModal.notvdbid": "Correlação Manual Necessária", "components.RequestModal.SearchByNameModal.nosummary": "Sinopse não encontrada para esse título.", "components.Login.signin": "Entrar", "components.UserList.userssaved": "Permissões de usuário salvas com sucesso!", @@ -402,8 +385,7 @@ "components.Settings.toastPlexConnectingFailure": "Falha ao se conectar ao Plex.", "components.Settings.toastPlexConnecting": "Tentando se conectar ao Plex…", "components.Settings.timeout": "Tempo limite excedido", - "components.Settings.settingUpPlexDescription": "Para configurar o Plex, você pode entrar com as configurações manualmente ou escolher um dos servidores disponívies obtivos de plex.tv. Clique no botão próximo à lista para atualizar e checar a conectividade com o servidor.", - "components.Settings.settingUpPlex": "Configurando Plex", + "components.Settings.settingUpPlexDescription": "Para configurar o Plex, você pode entrar com as configurações manualmente ou escolher um dos servidores disponívies obtivos de plex.tv. Clique no botão próximo à lista para obter os servidores disponíveis.", "components.Settings.serverpresetRefreshing": "Obtendo servidores…", "components.Settings.serverpresetPlaceholder": "Servidor Plex", "components.Settings.serverpresetManualMessage": "Configurar manualmente", @@ -412,11 +394,7 @@ "components.Settings.serverRemote": "remoto", "components.Settings.serverLocal": "local", "components.Settings.serverConnected": "conectado", - "components.Settings.notificationsettingssaved": "Configurações de notificação salvas com sucesso!", - "components.Settings.notificationsettingsfailed": "Falha ao salvar configurações de notificação.", - "components.Settings.notificationAgentsSettings": "Agentes de Notificação", - "components.Settings.notificationAgentSettingsDescription": "Escolha os tipos de notificações a enviar e quais agentes de notificação usar.", - "components.Settings.enablenotifications": "Habilitar Notificações", + "components.Settings.notificationAgentSettingsDescription": "Configure e habilite agentes de notificação.", "components.Settings.csrfProtectionTip": "Define acesso externo à API como apenas leitura (Requer HTTPS e é necessário reiniciar Overseerr para mudança ter efeito)", "components.Settings.csrfProtection": "Habilitar Proteção Contra CSRF", "components.PlexLoginButton.signinwithplex": "Entrar", @@ -510,7 +488,6 @@ "components.RequestModal.AdvancedRequester.requestas": "Solicitar Como", "components.Discover.discover": "Explorar", "components.AppDataWarning.dockerVolumeMissingDescription": "O ponto de montagem{appDataPath} não foi corretamente configurado. Todos dados serão perdidos quando o container parar ou reiniciar.", - "components.AppDataWarning.dockerVolumeMissing": "Faltando Ponto de Montagem do Volume Docker", "components.Settings.validationApplicationUrlTrailingSlash": "A URL não pode terminar com uma barra", "components.Settings.validationApplicationUrl": "Você deve prover uma URL válida", "components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "A URL não pode terminar com uma barra", @@ -560,10 +537,8 @@ "components.PermissionEdit.autoapprove4kSeries": "Aprovar Automaticamente Séries em 4K", "components.PermissionEdit.autoapprove4kMovies": "Aprovar Automaticamente Filmes em 4K", "components.PermissionEdit.autoapprove4kDescription": "Concede aprovação automática para todas solicitações em 4K feitas por esse usuário.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Essa conta de usuário não possui uma senha local em {applicationTitle}. Defina uma senha abaixo para permitir que essa conta entre como “usuário local.\"", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Você deve prover um token de acesso", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificações via Pushbullet você precisará criar um token de acesso e inserí-lo abaixo.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configurando Notificações Via Pushbullet", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificações via Pushbullet você precisará criar um token de acesso .", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Configurações de notificação via Pushbullet salvas com sucesso!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Falha ao salvar configurações de notificação via Pushover.", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "Você deve prover uma nova senha", @@ -573,7 +548,6 @@ "components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Usuário Plex", "components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Usuário Local", "components.UserProfile.recentrequests": "Solicitações Recentes", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Senha Não Definida", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Senha Atual", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Senha salva com sucesso!", "components.UserProfile.UserSettings.menuChangePass": "Senha", @@ -583,8 +557,7 @@ "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nova Senha", "components.UserProfile.UserSettings.menuNotifications": "Notificações", "components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Nome de Exibição", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID do Discord", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Habilitar Notificações", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID do Usuário", "components.UserProfile.ProfileHeader.settings": "Editar Configurações", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirme a Senha", "components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Permissões salvas com sucesso!", @@ -601,14 +574,13 @@ "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Algo deu errado ao salvar senha.", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "A senha é muito curta; Ela deve ter no mínimo 8 caractéres", "components.UserList.edituser": "Editar Permissões de Usuário", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notificação de teste enviada!", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Tipos de Notificação", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notificação Pushbullet de teste enviada!", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Habilitar Agente", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Token de Acesso", "components.Layout.UserDropdown.settings": "Configurações", "components.Layout.UserDropdown.myprofile": "Perfil", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Você deve prover um ID de usuário Discord válido", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "O ID correspondente ao seu usuário do Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Você deve prover um ID válido de usuário", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "O ID correspondente ao seu usuário", "components.CollectionDetails.requestswillbecreated4k": "Serão feitas solicitações em 4K dos seguintes títulos:", "components.CollectionDetails.requestcollection4k": "Solicitar Coleção em 4K", "components.UserProfile.UserSettings.UserGeneralSettings.region": "Região de Exploração", @@ -617,7 +589,6 @@ "components.Settings.region": "Região de Exploração", "components.Settings.originallanguage": "Idioma de Exploração", "components.Settings.email": "E-mail", - "components.Settings.Notifications.emailNotificationTypesAlert": "E-mail de Destinatários", "components.RegionSelector.regionDefault": "Todas Regiões", "components.Discover.upcomingtv": "Séries em Breve", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filtra conteúdo por disponibilidade na região", @@ -637,12 +608,11 @@ "components.Settings.SettingsJobsCache.download-sync": "Sincronizar Downloads", "components.Settings.SettingsJobsCache.download-sync-reset": "Limpar Sincronização de Download", "i18n.loading": "Carregando…", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Você deve prover um ID válido de chat do Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Você deve prover um ID válido de chat", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Inicie uma conversa, adicione @get_id_bot, e envie o comando /my_id", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Adicione @get_id_bot à conversa", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID de Chat do Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID de Chat", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Envia notificações sem som", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar Mensagens do Telegram Silenciosamente", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar Silenciosamente", "components.TvDetails.seasons": "{seasonCount, plural, one {# Temporada} other {# Temporadas}}", "components.Settings.SettingsJobsCache.unknownJob": "Tarefa Desconhecida", "components.Settings.Notifications.botUsername": "Usuário do Bot", @@ -666,11 +636,9 @@ "components.Settings.SettingsJobsCache.radarr-scan": "Escanemento do Radarr", "components.Settings.SettingsJobsCache.plex-recently-added-scan": "Recentemente Adicionado ao Plex", "components.Settings.SettingsJobsCache.plex-full-scan": "Escaneamento de Todas Bibliotecas do Plex", - "components.UserProfile.norequests": "Nenhuma Solicitação", + "components.UserProfile.norequests": "Nenhuma solicitação.", "components.UserProfile.UserSettings.unauthorizedDescription": "Você não tem permissão para modificar as configurações desse usuários.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "Você não pode modificar suas próprias permissões.", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Criptografa mensagens de e-mail", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "Chave PGP Pública", "components.UserProfile.ProfileHeader.userid": "ID de Usuário: {userid}", "components.UserProfile.ProfileHeader.joindate": "Criado em {joindate}", "components.Settings.menuUsers": "Usuários", @@ -680,10 +648,10 @@ "components.Settings.SettingsUsers.toastSettingsFailure": "Algo deu errado ao salvar configurações.", "components.Settings.SettingsUsers.localLogin": "Habilitar Autenticação Local", "components.Settings.SettingsUsers.defaultPermissions": "Permissões Padrão", - "components.Settings.Notifications.pgpPrivateKeyTip": "Assina mensagens encriptadas de e-mail (Senha PGP necessária)", - "components.Settings.Notifications.pgpPrivateKey": "Chave PGP privada", - "components.Settings.Notifications.pgpPasswordTip": "Assina mensagens encriptadas de e-mail (Chave privada PGP necessária)", - "components.Settings.Notifications.pgpPassword": "Senha PGP", + "components.Settings.Notifications.pgpPrivateKeyTip": "Assina mensagens encriptadas de e-mail usando OpenPGP", + "components.Settings.Notifications.pgpPrivateKey": "Chave PGP privada", + "components.Settings.Notifications.pgpPasswordTip": "Assina mensagens encriptadas de e-mail usando OpenPGP", + "components.Settings.Notifications.pgpPassword": "Senha PGP", "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Notificações de Mídia Aprovada, Mídia Recusada, e Mídia Disponível serão enviadas ao usuário que fez a solicitação.", "components.NotificationTypeSelector.mediaAutoApprovedDescription": "Envia uma notificação quando a mídia solicitada é aprovada automaticamente.", "components.NotificationTypeSelector.mediaAutoApproved": "Mídia Aprovada Automaticamente", @@ -701,7 +669,6 @@ "components.ResetPassword.passwordreset": "Redefinir Senha", "components.Settings.SettingsLogs.logDetails": "Detalhes do Log", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Algo deu errado ao salvar sua senha. Sua senha foi digitada corretamente?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Atualmente sua conta não possui uma senha especificamente para {applicationTitle}. Defina uma senha abaixo para habilitar autenticação local usando seu endereço de e-mail.", "components.Settings.cacheImagesTip": "Otimiza e armazena todas imagens localmente (consume um espaço significante do disco)", "pages.somethingwentwrong": "Algo deu errado", "pages.serviceunavailable": "Serviço Indisponível", @@ -742,7 +709,6 @@ "components.PersonDetails.alsoknownas": "Também Conhecido(a) Como: {names}", "i18n.delimitedlist": "{a}, {b}", "i18n.view": "Exibir", - "i18n.unauthorized": "Não Autorizado", "i18n.tvshow": "Série", "i18n.testing": "Testando…", "i18n.test": "Testar", @@ -792,5 +758,64 @@ "components.QuotaSelector.tvRequestLimit": "{quotaLimit} temporadas(s) a cada {quotaDays} dia(s)", "components.MovieDetails.originaltitle": "Título Original", "components.LanguageSelector.originalLanguageDefault": "Todos Idiomas", - "components.LanguageSelector.languageServerDefault": "Padrão ({language})" + "components.LanguageSelector.languageServerDefault": "Padrão ({language})", + "components.RequestModal.AdvancedRequester.notagoptions": "Nenhuma Tag.", + "components.Settings.SonarrModal.testFirstTags": "Teste a conexão para carregar as tags", + "components.Settings.SonarrModal.tags": "Tags", + "components.Settings.SonarrModal.selecttags": "Selecione as tags", + "components.Settings.SonarrModal.notagoptions": "Nenhuma tag.", + "components.Settings.SonarrModal.loadingTags": "Carregando tags…", + "components.Settings.SonarrModal.edit4ksonarr": "Editar Servidor Sonarr 4K", + "components.Settings.SonarrModal.default4kserver": "Servidor 4K Padrão", + "components.Settings.SonarrModal.create4ksonarr": "Adicionar Novo Servidor Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Tags Para Animes", + "components.Settings.RadarrModal.testFirstTags": "Teste a conexão para carregar as tags", + "components.Settings.RadarrModal.tags": "Tags", + "components.Settings.RadarrModal.selecttags": "Selecione as tags", + "components.Settings.RadarrModal.notagoptions": "Nenhuma tag.", + "components.Settings.RadarrModal.loadingTags": "Carregando tags…", + "components.Settings.RadarrModal.edit4kradarr": "Editar Servidor Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Servidor 4K Padrão", + "components.Settings.RadarrModal.create4kradarr": "Adicionar Novo Servidor Radarr 4K", + "components.RequestModal.AdvancedRequester.tags": "Tags", + "components.RequestModal.AdvancedRequester.selecttags": "Selecione as tags", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Esse usuário ainda não possui uma senha definida. Defina uma senha abaixo para habilitar autenticação local usando seu endereço de e-mail.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Esse usuário ainda não possui uma senha definida. Defina uma senha abaixo para habilitar autenticação como \"usuário local.\"", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Você deve prover uma chave pública PGP válida", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Criptografa mensagens de e-mail usando OpenPGP", + "components.Settings.serviceSettingsDescription": "Configure seu(s) servidor(es) {serverType} abaixo. Você pode se conectar à múltiplos servidores {serverType}, mas apenas dois podem ser marcados como padrão (um não 4K e outro 4K). Administradores podem sobrescrever o servidor usado antes de aprovar as novas solicitações.", + "components.Settings.noDefaultServer": "Ao menos um servidor {serverType} deve ser marcado como padrão para que as solicitações de {mediaType} sejam processadas.", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Configura??es de notifica??o via Telegram salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Falha ao salvar configura??es de notifica??o via Telegram.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Chave P¨²blica PGP", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Habilitar Notifica??es", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Habilitar Notifica??es", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Habilitar Men??es", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Configura??es de notifica??o via e-mail salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Falha ao salvar configura??es de notifica??o via e-mail.", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "E-mail", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Configura??es de notifica??o via Discord salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Falha ao salvar configura??es de notifica??o via Discord.", + "components.Settings.noDefaultNon4kServer": "Se voc¨º tem apenas um servidor {serverType} para conte¨²do 4K e n?o 4K (ou se voc¨º baixa apenas conte¨²do 4K), seu servidor {serverType} N?O deve ser designado como um servidor 4K.", + "components.Settings.mediaTypeSeries": "s¨¦rie", + "components.Settings.mediaTypeMovie": "filme", + "components.Settings.SettingsAbout.uptodate": "Atualizado", + "components.Settings.SettingsAbout.outofdate": "Desatualizado", + "components.Settings.Notifications.validationPgpPrivateKey": "Voc¨º deve prover uma chave PGP privada se uma senha foi inserida", + "components.Settings.Notifications.validationPgpPassword": "Voc¨º deve prover uma senha se uma chave PGP privada foi inserida", + "components.Settings.Notifications.botUsernameTip": "Permitir que usu¨¢rios iniciem uma conversa com o bot e configure suas pr¨®prias notifica??es", + "components.RequestModal.pendingapproval": "Sua solicita??o est¨¢ aguardando aprova??o.", + "components.RequestList.RequestItem.mediaerror": "O t¨ªtulo associado ¨¤ essa solicita??o n?o est¨¢ mais dispon¨ªvel.", + "components.RequestList.RequestItem.deleterequest": "Apagar Solicita??o", + "components.RequestList.RequestItem.cancelRequest": "Cancelar Solicita??o", + "components.RequestCard.mediaerror": "O t¨ªtulo associado ¨¤ essa solicita??o n?o est¨¢ mais dispon¨ªvel.", + "components.RequestCard.deleterequest": "Apagar Solicita??o", + "components.NotificationTypeSelector.notificationTypes": "Tipos de Notificação", + "components.Layout.VersionStatus.streamstable": "Overseerr Estável", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Desenv.", + "components.Layout.VersionStatus.outofdate": "Desatualizado", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {versão} other {versões}} atrasado(a)", + "components.Discover.noRequests": "Nenhuma solicitação.", + "components.UserList.autogeneratepasswordTip": "Envia para o usuário uma senha gerada automaticamente", + "components.Layout.betawarning": "Essa é uma versão BETA. Algumas funcionalidades podem ser instáveis ou não funcionarem. Por favor reporte qualquer problema no GitHub!" } diff --git a/src/i18n/locale/pt_PT.json b/src/i18n/locale/pt_PT.json index 24914456..0e68f9cd 100644 --- a/src/i18n/locale/pt_PT.json +++ b/src/i18n/locale/pt_PT.json @@ -30,7 +30,7 @@ "components.Settings.RadarrModal.add": "Adicionar Servidor", "components.Settings.Notifications.webhookUrlPlaceholder": "Configurações do Servidor → Integrações → Webhooks", "components.Settings.Notifications.validationSmtpPortRequired": "Você deve fornecer um número de porta válido", - "components.Settings.Notifications.validationSmtpHostRequired": "Você deve fornecer um nome de host ou endereço IP", + "components.Settings.Notifications.validationSmtpHostRequired": "Você deve fornecer um nome de host ou endereço IP válido", "components.Settings.Notifications.validationChatIdRequired": "Você deve fornecer um ID de chat válido", "components.Settings.Notifications.validationBotAPIRequired": "Você deve fornecer um token de autenticação de bot", "components.Settings.Notifications.telegramsettingssaved": "Configurações de notificação Telegram salvas com sucesso!", @@ -39,7 +39,6 @@ "components.Settings.Notifications.smtpPort": "Porta SMTP", "components.Settings.Notifications.smtpHost": "Servidor SMTP", "components.Settings.Notifications.settinguptelegramDescription": "Para configurar notificações Telegram, você precisará criar um bot e obter a chave API do bot. Além disso, você precisará do ID do chat para o qual você deseja enviar notificações. Você pode encontrar isso adicionando @get_id_bot ao chat e inserindo o comando /my_id.", - "components.Settings.Notifications.settinguptelegram": "Configurando notificações Telegram", "components.Settings.Notifications.senderName": "Nome do Remetente", "components.Settings.Notifications.enableSsl": "Ativar SSL", "components.Settings.Notifications.emailsettingssaved": "Configurações de notificação e-mail salvas com sucesso!", @@ -65,26 +64,20 @@ "components.Settings.Notifications.webhookUrl": "URL de Webhook", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "URL de Webhook", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "URL de Webhook", - "components.Settings.Notifications.NotificationsSlack.testsent": "Notificação de teste enviada!", - "components.Settings.Notifications.testsent": "Notificação de teste enviada!", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Notificação de teste enviada!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Notificação de teste Slack enviada!", + "components.Settings.Notifications.testsent": "Notificação de teste Telegram enviada!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Notificação de teste Webhook enviada!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Configurações de notificação Slack salvas com sucesso!", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Falhou o salvar das configurações de notificação do Slack.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "Para configurar notificações Slack, você precisará criar uma integração Webhook de entrada insire o URL do webhook fornecido abaixo.", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar notificações Pushover, você precisará registrar uma aplicação e inserir o token do API abaixo. (Você pode utilizar um dos nossos ícones oficiais no GitHub.) Você também precisará da sua chave de utilizador.", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Configurando Notificações Pushover", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Configurando Notificações Slack", - "components.Settings.Notifications.notificationtypes": "Tipos de Notificação", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Tipos de Notificação", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Tipos de Notificação", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "Para configurar notificações Pushover, você precisará registrar uma aplicação e inserir o token do API abaixo. (Você pode utilizar um dos ícones Overseerr oficiais no GitHub.)", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Ativar Agente", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Você deve fornecer uma chave de utilizador válida", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Você deve fornecer um token de aplicação válido", - "components.Settings.Notifications.NotificationsPushover.userToken": "Chave de Utilizador", - "components.Settings.Notifications.NotificationsPushover.testsent": "Notificação de teste enviada!", + "components.Settings.Notifications.NotificationsPushover.userToken": "Chave de Utilizador ou Grupo", + "components.Settings.Notifications.NotificationsPushover.testsent": "Notificação de teste Pushover enviada!", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Configurações de notificação Pushover salvas com sucesso!", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "O salvar das configurações de notificação Pushover falhou.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Tipos de Notificação", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Ativar Agente", "components.Settings.Notifications.NotificationsPushover.accessToken": "Token de Aplicação/API", "components.Search.searchresults": "Resultados da Pesquisa", @@ -164,7 +157,7 @@ "components.MovieDetails.originallanguage": "Língua original", "components.MovieDetails.manageModalTitle": "Gerir Filme", "components.MovieDetails.manageModalRequests": "Solicitações", - "components.MovieDetails.manageModalNoRequests": "Nenhuma Solicitação", + "components.MovieDetails.manageModalNoRequests": "Nenhuma solicitação.", "components.MovieDetails.manageModalClearMediaWarning": "* Isso removerá irreversivelmente todos os dados desse filme, incluindo todas as solicitações. Se esse item existir em sua biblioteca Plex, as informações de mídia serão recriadas durante o próximo escaneamento.", "components.MovieDetails.manageModalClearMedia": "Limpar Todos Dados de Mídia", "components.MovieDetails.cast": "Elenco", @@ -178,7 +171,6 @@ "components.Login.loginerror": "Algo errou tentando a conectar-se.", "components.Login.password": "Palavra-passe", "components.Login.email": "Endereço E-mail", - "components.Layout.alphawarning": "Este software está na versão ALPHA. Funcionalidades podeem quebrar ou se tornar instável. Por favor, reporte qualquer problema no GitHub!", "components.Layout.UserDropdown.signout": "Sair", "components.Layout.Sidebar.users": "Utilizadores", "components.Layout.Sidebar.settings": "Configurações", @@ -193,7 +185,6 @@ "components.Discover.recentlyAdded": "Adicionado Recentemente", "components.Discover.populartv": "Séries Populares", "components.Discover.popularmovies": "Filmes Populares", - "components.Discover.nopending": "Nenhuma Solicitação Pendente", "components.Discover.discovertv": "Séries Populares", "components.Discover.discovermovies": "Filmes Populares", "components.CollectionDetails.requestswillbecreated": "Os títulos seguintes terão solicitações criadas para eles:", @@ -227,8 +218,7 @@ "components.UserList.totalrequests": "Solicitações Totais", "components.UserList.role": "Função", "components.UserList.plexuser": "Utilizador Plex", - "components.UserList.passwordinfodescription": "Para utilizar a geração automática de palavras-passe, as notificações por e-mail precisam ser configuradas e ativadas.", - "components.UserList.passwordinfo": "Informações de Palavra-passe", + "components.UserList.passwordinfodescription": "Ativar as notificações por e-mail para permitir a geração automática de palavra-passe.", "components.UserList.localuser": "Utilizador Local", "components.UserList.lastupdated": "Última Atualização", "components.UserList.importfromplexerror": "Algo errou importando utilizadores do Plex.", @@ -236,7 +226,7 @@ "components.UserList.importedfromplex": "{userCount, plural, =0 {Nenhum novo utilizador} one {# novo utilizador} other {# novos utilizadores}} importado(s) do Plex com sucesso!", "components.UserList.email": "Endereço de E-mail", "components.UserList.deleteuser": "Apagar Utilizador", - "components.UserList.deleteconfirm": "Tem certeza que deseja apagar esse utilizador? Todas informações de solicitação desse utilizador serão apagas.", + "components.UserList.deleteconfirm": "Tem certeza que deseja apagar esse utilizador? Todos os seus dados de solicitação serão removidos permanentemente.", "components.UserList.creating": "Criando…", "components.UserList.createuser": "Criar Utilizador", "components.UserList.createlocaluser": "Criar Utilizador Local", @@ -255,21 +245,16 @@ "components.Settings.toastApiKeyFailure": "Algo errou gerando uma nova chave API.", "components.Settings.startscan": "Iniciar Scaneamento", "components.Settings.sonarrsettings": "Configurações do Sonarr", - "components.Settings.sonarrSettingsDescription": "Configure sua conexão Radarr abaixo. Você pode ter várias configurações Radarr, mas apenas duas podem estar ativas como padrão a qualquer momento (uma para padrão HD e outra para 4K). Os administradores podem substituir o servidor que é usado para novas solicitações.", "components.Settings.servernamePlaceholder": "Nome do Servidor Plex", "components.Settings.servername": "Nome do Servidor", "components.Settings.radarrsettings": "Configurações do Radarr", - "components.Settings.radarrSettingsDescription": "Configure abaixo sua conexão com Radarr. Você pode ter várias configurações Radarr, mas apenas duas podem estar ativas como padrão a qualquer momento (uma para padrão HD e outra para 4K). Os administradores podem substituir o servidor que é usado para novas solicitações.", "components.Settings.port": "Porta", "components.Settings.plexsettingsDescription": "Define as configurações para o seu servidor Plex. Overseerr escaneará sua biblioteca em intervalos e verá qual conteúdo está disponível.", "components.Settings.plexlibraries": "Bibliotecas do Plex", "components.Settings.plexsettings": "Configurações do Plex", "components.Settings.plexlibrariesDescription": "Bibliotecas que Overseerr escaneará por títulos. Configure e salve as informações de conexão com Plex e clique no botão abaixo se nenhuma biblioteca é listada.", "components.Settings.notrunning": "Parado", - "components.Settings.notificationsettingsDescription": "Define as configurações de notificação global. As configurações abaixo afetarão todos os agentes de notificação.", "components.Settings.notificationsettings": "Configurações de Notificação", - "components.Settings.nodefaultdescription": "Ao menos um servidor deve ser selecionado como padrão antes que qualquer solicitação chegue aos seus serviços.", - "components.Settings.nodefault": "Nenhum Servidor Padrão", "components.Settings.menuServices": "Serviços", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuNotifications": "Notificações", @@ -343,7 +328,6 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Ver Mudanças", "components.Settings.SettingsAbout.Releases.versionChangelog": "Mudanças Nesta Versão", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "As últimas mudanças na branch develop do Overseerr não são mostradas abaixo. Por favor, veja o histórico de commits para esta branch no GitHub para detalhes.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Versão de Desenvolvimento", "components.Settings.SettingsAbout.Releases.releases": "Versões", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Informações de versão indisponíveis. O GitHub está abaixo?", "components.Settings.SettingsAbout.Releases.latestversion": "Atual", @@ -358,7 +342,7 @@ "components.UserList.password": "Palavra-passe", "components.UserList.created": "Criado", "components.UserList.create": "Criar", - "components.UserList.autogeneratepassword": "Gerar palavra-passe automaticamente", + "components.UserList.autogeneratepassword": "Gerar Palavra-passe Automaticamente", "i18n.request": "Solicitar", "components.UserList.admin": "Administrador", "components.TvDetails.watchtrailer": "Ver Trailer", @@ -374,7 +358,7 @@ "components.TvDetails.network": "{networkCount, plural, one {Emissor} other {Emissores}}", "components.TvDetails.manageModalTitle": "Gerir Série", "components.TvDetails.manageModalRequests": "Solicitações", - "components.TvDetails.manageModalNoRequests": "Nenhuma Solicitação", + "components.TvDetails.manageModalNoRequests": "Nenhuma solicitação.", "components.TvDetails.manageModalClearMediaWarning": "* Isso removerá irreversivelmente todos os dados dessa séries, incluindo todas as solicitações. Se esse item existir em sua biblioteca Plex, as informações de mídia serão recriadas durante o próximo escaneamento.", "components.TvDetails.manageModalClearMedia": "Limpar Todos Dados de Mídia", "components.TvDetails.firstAirDate": "Primeira Exibição", @@ -391,16 +375,11 @@ "components.Login.signinwithplex": "Conecte-se com sua conta Plex", "components.RequestModal.requesterror": "Algo errou tentando submeter a solicitação.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Não foi possível associar sua solicitação automaticamente. Por favor selecione a associação correta na lista abaixo.", - "components.RequestModal.SearchByNameModal.notvdbid": "Associação Manual Necessária", "components.RequestModal.SearchByNameModal.nosummary": "Sinopse não encontrada para este título.", "components.Login.signinheader": "Conecte-se para continuar", "components.Login.signingin": "Conectando…", "components.Login.signin": "Conecte-se", - "components.Settings.notificationsettingssaved": "Configurações de notificação salvas com sucesso!", - "components.Settings.enablenotifications": "Ativar notificações", - "components.Settings.notificationsettingsfailed": "Falhou a salvar as configurações de notificação.", - "components.Settings.notificationAgentsSettings": "Agentes de Notificação", - "components.Settings.notificationAgentSettingsDescription": "Escolhe os tipos de notificações a enviar e quais agentes de notificação utilizar.", + "components.Settings.notificationAgentSettingsDescription": "Configurar e ativar agentes de notificação.", "components.PlexLoginButton.signinwithplex": "Conecte-se", "components.PlexLoginButton.signingin": "Conectando…", "components.UserList.userssaved": "Permissões de utilizador salvas com sucesso!", @@ -412,8 +391,7 @@ "components.Settings.toastPlexConnectingFailure": "Falha ao conectar ao Plex.", "components.Settings.toastPlexConnecting": "Tentando conectar ao Plex…", "components.Settings.timeout": "Timeout", - "components.Settings.settingUpPlexDescription": "Para configurar o Plex, você pode inserir seus detalhes manualmente ou selecionar um dos servidores disponíveis obtidos de plex.tv. Clique o botão à direita da lista suspensa para verificar a conectividade e recuperar os servidores disponíveis.", - "components.Settings.settingUpPlex": "Configurando Plex", + "components.Settings.settingUpPlexDescription": "Para configurar o Plex, você pode inserir seus detalhes manualmente ou selecionar um dos servidores disponíveis obtidos de plex.tv. Clique no botão à direita do dropdown para obter a lista de servidores disponíveis.", "components.Settings.serverpresetRefreshing": "Obtendo servidores…", "components.Settings.serverpresetPlaceholder": "Servidor Plex", "components.Settings.serverpresetManualMessage": "Configuração Manual", @@ -517,7 +495,6 @@ "components.PermissionEdit.viewrequestsDescription": "Conceder permissão para ver solicitações de outros utilizadores.", "components.PermissionEdit.viewrequests": "Ver Solicitações", "components.Discover.discover": "Descobrir", - "components.AppDataWarning.dockerVolumeMissing": "Ponto de Montagem do Volume Docker Faltando", "components.AppDataWarning.dockerVolumeMissingDescription": "O ponto de montagem {appDataPath} não foi configurado corretamente . Todos dados serão perdidos quando o container parar ou reiniciar.", "components.TvDetails.nextAirDate": "Próxima Data de Transmissão", "components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "URL Base não deve terminar com uma barra", @@ -574,14 +551,12 @@ "components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "Você deve confirmar a nova palavra-passe", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Palavra-passe salva com sucesso!", "components.UserProfile.UserSettings.UserPasswordChange.password": "Palavra-passe", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Nehuma Palavra-pase Definida", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nova Palavra-passe", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Palavra-passe Atual", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirmar Palavra-passe", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Configurações de notificação salvas com sucesso!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Algo errou salvando as configurações.", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Configurações de Notificação", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Ativar notificações", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Configurações salvas com sucesso!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Algo errou salvando as configurações.", "components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Utilizador Plex", @@ -592,21 +567,18 @@ "components.UserProfile.ProfileHeader.profile": "Ver Perfil", "components.UserList.edituser": "Modificar Permissões do Utilizador", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Você deve fornecer um token de acesso", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notificação de teste enviada!", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Tipos de Notificação", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Notificação de teste Pushbullet enviada!", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Ativar Agente", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Token de Acesso", "components.Layout.UserDropdown.settings": "Configurações", "components.Layout.UserDropdown.myprofile": "Perfil", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Essa conta de utilizador não tem uma palavra-passe specifica para {applicationTitle}. Configure uma palavra-passe abaixo para permitir que essa conta entre como “utilizador local”.", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "Palavra-passe muito curta; necessário ter no mínimo 8 caracteres", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Algo errou ao salvar a palavra-passe.", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Você deve fornecer um ID de utilizador Discord válido", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "O ID ao seu utilizador do Discord", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID do Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Você deve fornecer um ID de utilizador válido", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "O número de ID para sua conta de utilizador", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "ID de Utilizador", "components.UserList.userfail": "Ocorreu um erro ao salvar as permissões do utilizador.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificações Pushbullet, você precisará criar um token de acesso e inseri-lo abaixo.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Configurando Notificações Pushbullet", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "Para configurar notificações Pushbullet, você precisará criar um token de acesso.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Configurações de notificação Pushbullet salvas com sucesso!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Falhou o salvar das configurações de notificação Pushbullet.", "components.CollectionDetails.requestswillbecreated4k": "Os seguintes títulos terão solicitações de 4K criadas para eles:", @@ -624,7 +596,6 @@ "components.Settings.webhook": "Webhook", "components.Settings.email": "E-Mail", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "As notificações por e-mail de Mídia Solicitada, Mídia Aprovada Automaticamente e Mídia Falhou são enviadas a todos os utilizadores com a permissão Gerir Solicitações .", - "components.Settings.Notifications.emailNotificationTypesAlert": "Destinatários de Notificação de E-mail", "components.RegionSelector.regionServerDefault": "Padrão ({region})", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "Você não tem permissão para modificar a palavra-passe deste utilizador.", "components.UserProfile.UserSettings.UserGeneralSettings.user": "Utilizador", @@ -635,12 +606,11 @@ "components.UserList.owner": "Proprietário", "components.UserList.accounttype": "Tipo de Conta", "i18n.loading": "Carregando…", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Você deve fornecer um ID de chat Telegram válido", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Você deve fornecer um ID de chat válido", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Iniciar um chat, adicionar @get_id_bot, e enviar o comando /my_id", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Adicionar @get_id_bot ao chat", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID de Chat do Telegram", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "ID do Chat", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Envia notificações sem som", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar Mensagens Telegram Silenciosamente", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Enviar Silenciosamente", "components.TvDetails.seasons": "{seasonCount, plural, one {# Temporada} other {# Temporadas}}", "components.Settings.SettingsJobsCache.unknownJob": "Tarefa Desconhecida", "components.Settings.SettingsJobsCache.download-sync-reset": "Reiniciar Sincronização de Download", @@ -680,15 +650,13 @@ "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": "Notificações por e-mail de Mídia Aprovada, Mídia Rejeitada e Mídia Disponível são enviadas ao utilizador que enviou a solicitação.", "components.NotificationTypeSelector.mediaAutoApprovedDescription": "Envia uma notificação quando a mídia solicitada é aprovada automaticamente.", "components.NotificationTypeSelector.mediaAutoApproved": "Mídia Aprovada Automaticamente", - "components.UserProfile.norequests": "Nenhuma Solicitação", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Encriptar mensagens e-mail", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "Chave PGP Pública", + "components.UserProfile.norequests": "Nenhuma solicitação.", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minutos", "components.TvDetails.episodeRuntime": "Duração do Episódio", - "components.Settings.Notifications.pgpPrivateKeyTip": "Assinar mensagens de e-mail encriptadas (Palavra-passe PGP também é necessária)", - "components.Settings.Notifications.pgpPasswordTip": "Assinar mensagens de e-mail encriptadas (Chave privada PGP também é necessária)", - "components.Settings.Notifications.pgpPrivateKey": "Chave Privada PGP", - "components.Settings.Notifications.pgpPassword": "Palavra-passe PGP", + "components.Settings.Notifications.pgpPrivateKeyTip": "Assinar mensagens de e-mail encriptadas utilizando OpenPGP", + "components.Settings.Notifications.pgpPasswordTip": "Assinar mensagens de e-mail encriptadas utilizando OpenPGP", + "components.Settings.Notifications.pgpPrivateKey": "Chave Privada PGP", + "components.Settings.Notifications.pgpPassword": "Palavra-passe PGP", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.Settings.partialRequestsEnabled": "Permitir Solicitações Parciais de Séries", "components.RequestModal.requestall": "Solicitar Todas as Temporadas", @@ -705,7 +673,6 @@ "pages.internalservererror": "Erro Interno do Servidor", "i18n.usersettings": "Utilizadores", "i18n.settings": "Configurações", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Atualmente, sua conta não tem uma palavra-passe específica para {applicationTitle}. Configure uma palavra-passe abaixo para permitir a conexão como um \"utilizador local\" usando seu endereço e-mail.", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notificações", "components.Settings.services": "Serviços", "components.Settings.plex": "Plex", @@ -763,14 +730,13 @@ "components.Settings.SettingsUsers.movieRequestLimitLabel": "Limite Global de Solicitações de Filmes", "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {temporada} other {temporadas}}", "components.RequestModal.QuotaDisplay.season": "temporada", - "components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {Nenhuma} other {#}} {type} {remaining, plural, one {solicitação restante} other {solicitações restantes}}", + "components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {Nenhuma} other {#}} {remaining, plural, one {solicitação de {type} restante} other {solicitações de {type}s restantes}}", "components.RequestModal.QuotaDisplay.quotaLinkUser": "Você pode ver um resumo dos limites de solicitação deste utilizador em sua página de perfil.", "components.RequestModal.QuotaDisplay.quotaLink": "Você pode ver um resumo dos seus limites de solicitação em sua página de perfil.", "components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Não há solicitações de temporada suficientes restantes", "i18n.next": "Próxima", "i18n.all": "Todas", "i18n.view": "Ver", - "i18n.unauthorized": "Não Aautorizado", "i18n.tvshow": "Séries", "i18n.testing": "Testando…", "i18n.test": "Teste", @@ -790,5 +756,66 @@ "i18n.areyousure": "Tem certeza?", "components.TvDetails.originaltitle": "Título Original", "components.RequestModal.QuotaDisplay.requiredquotaUser": "Este utilizador precisa ter pelo menos {seasons} {seasons, plural, one {solicitação de temporada} other {solicitações de temporadas}} restantes para enviar uma solicitação para esta série.", - "components.MovieDetails.originaltitle": "Título Original" + "components.MovieDetails.originaltitle": "Título Original", + "components.LanguageSelector.originalLanguageDefault": "Todos Idiomas", + "components.LanguageSelector.languageServerDefault": "Padrão ({language})", + "components.Settings.SonarrModal.loadingTags": "Carregando tags…", + "components.Settings.SonarrModal.edit4ksonarr": "Modificar Servidor Sonarr 4K", + "components.Settings.SonarrModal.default4kserver": "Servidor 4K Padrão", + "components.Settings.SonarrModal.create4ksonarr": "Adicionar Novo Servidor Sonarr 4K", + "components.Settings.SonarrModal.animeTags": "Tags Para Animes", + "components.Settings.SonarrModal.testFirstTags": "Testar a conexão para carregar os tags", + "components.Settings.RadarrModal.testFirstTags": "Testar a conexão para carregar os tags", + "components.Settings.SonarrModal.tags": "Tags", + "components.Settings.RadarrModal.tags": "Tags", + "components.Settings.SonarrModal.selecttags": "Selecionar tags", + "components.Settings.RadarrModal.selecttags": "Selecionar tags", + "components.Settings.SonarrModal.notagoptions": "Nenhum tag.", + "components.Settings.RadarrModal.notagoptions": "Nenhum tag.", + "components.Settings.RadarrModal.loadingTags": "Carregando tags…", + "components.Settings.RadarrModal.edit4kradarr": "Modificar Servidor Radarr 4K", + "components.Settings.RadarrModal.default4kserver": "Servidor 4K Padrão", + "components.Settings.RadarrModal.create4kradarr": "Adicionar Novo Servidor Radarr 4K", + "components.RequestModal.AdvancedRequester.tags": "Tags", + "components.RequestModal.AdvancedRequester.selecttags": "Selecionar tags", + "components.RequestModal.AdvancedRequester.notagoptions": "Nenhum tag.", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Você deve fornecer uma chave pública PGP válida", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Chave Pública PGP", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Encriptar mensagens de e-mail usando OpenPGP ", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Ativar Notificações", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Ativar Notificações", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Ativar Menções", + "components.Settings.Notifications.validationPgpPrivateKey": "Você deve fornecer uma chave privada PGP válida se uma palavra-passe PGP for inserida", + "components.Settings.Notifications.validationPgpPassword": "Você deve fornecer uma palavra-passe PGP se uma chave privada PGP for inserida", + "components.Settings.Notifications.botUsernameTip": "Permitir que os utilizadores iniciem um chat com o bot e configurem suas próprias notificações pessoais", + "components.RequestModal.pendingapproval": "Sua solicitação está com aprovação pendente.", + "components.RequestList.RequestItem.mediaerror": "O título associado a esta solicitação não está mais disponível.", + "components.RequestList.RequestItem.deleterequest": "Apagar Solicitação", + "components.RequestCard.mediaerror": "O título associado a esta solicitação não está mais disponível.", + "components.RequestCard.deleterequest": "Apagar Solicitação", + "components.NotificationTypeSelector.notificationTypes": "Tipos de Notificação", + "components.Layout.VersionStatus.streamstable": "Overseerr Stable", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Develop", + "components.Layout.VersionStatus.outofdate": "Desatual", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} atrás", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Configurações de notificação Telegram salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Falhou o salvar das configurações de notificação Telegram.", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Configurações de notificação e-mail salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Falhou o salvar das configurações de notificação e-mail.", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "E-Mail", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Configurações de notificação Discord salvas com sucesso!", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Falhou o salvar das configurações de notificação Discord.", + "components.RequestList.RequestItem.cancelRequest": "Cancelar Solicitação", + "components.Discover.noRequests": "Nenhuma solicitação.", + "components.Settings.serviceSettingsDescription": "Configure seu(s) servidor(es) {serverType} abaixo. Você pode conectar vários servidores {serverType}, mas apenas dois deles podem ser marcados como padrões (um não 4K e um 4K). Os administradores podem mudar o servidor usado para processar novas solicitações antes da aprovação.", + "components.Settings.noDefaultServer": "Pelo menos um servidor {serverType} deve ser marcado como padrão para que as solicitações de {mediaType} sejam processadas.", + "components.Settings.noDefaultNon4kServer": "Se você tiver apenas um único servidor {serverType} para conteúdo não 4K e 4K (ou se você apenas carrega conteúdo 4K), seu servidor {serverType} NÃO deve ser designado como um servidor 4K.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Atualmente, sua conta não tem uma palavra-passe definida. Configure uma palavra-passe abaixo para permitir a conexão como um \"utilizador local\" usando seu e-mail.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Atualmente, a conta deste utilizador não tem uma palavra-passe definida. Configure uma palavra-passe abaixo para permitir que esta conta se conecte como um \"utilizador local\".", + "components.Settings.mediaTypeSeries": "série", + "components.Settings.mediaTypeMovie": "filme", + "components.Settings.SettingsAbout.uptodate": "Atualizado", + "components.Settings.SettingsAbout.outofdate": "Desatual", + "components.Layout.betawarning": "Isto é software BETA. Os recursos podem estar corrompidos e / ou instáveis. Relate qualquer problema no GitHub!", + "components.UserList.autogeneratepasswordTip": "Enviar uma palavra-passe gerada pelo servidor para o utilizador por e-mail" } diff --git a/src/i18n/locale/ru.json b/src/i18n/locale/ru.json index 5ba2aa08..bb9b5f56 100644 --- a/src/i18n/locale/ru.json +++ b/src/i18n/locale/ru.json @@ -1,7 +1,6 @@ { "components.Discover.discovermovies": "Популярные фильмы", "components.Discover.discovertv": "Популярные серии", - "components.Discover.nopending": "Нет отложенных запросов", "components.Discover.popularmovies": "Популярные фильмы", "components.Discover.populartv": "Популярные серии", "components.Discover.recentlyAdded": "Недавно добавленные", @@ -16,7 +15,6 @@ "components.Layout.Sidebar.settings": "Настройки", "components.Layout.Sidebar.users": "Пользователи", "components.Layout.UserDropdown.signout": "Выход", - "components.Layout.alphawarning": "Это АЛЬФА-версия этой программы. Почти все может быть сломано и/или нестабильно. Пожалуйста, сообщайте о проблемах на GitHub Overseerr!", "components.MovieDetails.budget": "Бюджет", "components.MovieDetails.cast": "В ролях", "components.MovieDetails.manageModalClearMedia": "Очистить все медиаданные", @@ -140,18 +138,15 @@ "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuServices": "", "components.Settings.notificationsettings": "Настройки уведомлений", - "components.Settings.notificationsettingsDescription": "", "components.Settings.notrunning": "", "components.Settings.plexlibraries": "Библиотеки Plex", "components.Settings.plexlibrariesDescription": "", "components.Settings.plexsettings": "Настройки Plex", "components.Settings.plexsettingsDescription": "", "components.Settings.port": "Порт", - "components.Settings.radarrSettingsDescription": "", "components.Settings.radarrsettings": "", "components.Settings.servername": "Название сервера", "components.Settings.servernamePlaceholder": "Название сервера Plex", - "components.Settings.sonarrSettingsDescription": "", "components.Settings.sonarrsettings": "", "components.Settings.ssl": "SSL", "components.Settings.startscan": "Начать сканирование", @@ -208,7 +203,6 @@ "components.Settings.SettingsAbout.totalrequests": "Всего запросов", "components.UserList.sortRequests": "Количество запросов", "components.UserList.sortCreated": "Дата создания", - "components.UserList.passwordinfo": "Информация о пароле", "components.Login.password": "Пароль", "components.UserList.password": "Пароль", "components.UserList.localuser": "Локальный пользователь", @@ -226,9 +220,6 @@ "components.Settings.serverpresetPlaceholder": "Сервер Plex", "components.Settings.serverpresetManualMessage": "Ручная настройка", "components.Settings.serverpreset": "Сервер", - "components.Settings.notificationsettingssaved": "Настройки уведомлений успешно сохранены!", - "components.Settings.nodefault": "Нет сервера по умолчанию", - "components.Settings.enablenotifications": "Включить уведомления", "i18n.deleting": "Удаление…", "components.Settings.applicationTitle": "Название приложения", "components.Settings.SettingsAbout.Releases.latestversion": "Самый последний", @@ -243,13 +234,9 @@ "components.Settings.Notifications.telegramsettingssaved": "Настройки уведомлений Telegram успешно сохранены!", "components.Settings.Notifications.senderName": "Имя отправителя", "components.Settings.Notifications.botAPI": "Токен аутентификации бота", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Типы уведомлений", - "components.Settings.Notifications.notificationtypes": "Типы уведомлений", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Агент включен", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Агент включен", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Агент включен", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Типы уведомлений", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Типы уведомлений", "components.Search.search": "Поиск", "components.ResetPassword.resetpassword": "Сбросить пароль", "components.ResetPassword.password": "Пароль", @@ -289,7 +276,6 @@ "components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "Вы должны указать действительный URL-адрес", "components.Settings.Notifications.NotificationsPushover.userToken": "Ключ пользователя", "components.Settings.Notifications.NotificationsPushbullet.testSent": "Тестовое уведомление отправлено!", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Типы уведомлений", "components.UserList.email": "Адрес электронной почты", "components.ResetPassword.email": "Адрес электронной почты", "components.Settings.SonarrModal.languageprofile": "Языковой профиль", diff --git a/src/i18n/locale/sr.json b/src/i18n/locale/sr.json index 0331c8dc..9756835d 100644 --- a/src/i18n/locale/sr.json +++ b/src/i18n/locale/sr.json @@ -62,20 +62,15 @@ "components.Settings.startscan": "Pokreni Skeniranje", "components.Settings.ssl": "SSL", "components.Settings.sonarrsettings": "Sonarr Podešavanja", - "components.Settings.sonarrSettingsDescription": "Podesite vaš Sonarr server ispod. Možete imati više, ali samo 2 mogu biti aktivna u bilo kom trenutku (jedan za HD, drugi za 4K). Administratori mogu da odaberu koji server je za nove zahteve.", "components.Settings.servernamePlaceholder": "Ime Plex Servera", "components.Settings.servername": "Ime Servera (Automatski se podesi kada sačuvate)", "components.Settings.radarrsettings": "Radarr Podešavanja", - "components.Settings.radarrSettingsDescription": "Podesite vaš Radarr server ispod. Možete imati više od jednog, ali samo 2 mogu biti aktivna u bilo kom trenutku (jedan za HD, drugi za 4K). Administratori mogu da odaberu koji server je za nove zahteve.", "components.Settings.port": "Port", "components.Settings.plexsettingsDescription": "Konfigurišite podešavanja za Vaš Plex server. Overseerr koristi vaš Plex server da skenira vaš sadržaj u nekom intervalu da proveri šta je dostupno.", "components.Settings.plexsettings": "Plex Podešavanja", "components.Settings.plexlibrariesDescription": "Overseerr skenira sadržaj za imena. Dodajte informacije o Plex konekciji i kliknite dole dugme ako nijedan nije na listi.", "components.Settings.plexlibraries": "Plex Sadržaj", - "components.Settings.notificationsettingsDescription": "Ovde možete odabrati tipove notifikacija koji se šalju i ka kojim servisima.", "components.Settings.notificationsettings": "Podešavanje Notifikacija", - "components.Settings.nodefaultdescription": "Barem jedan server mora biti označen kao defaultni da bi se zahtevi poslali ka servisima.", - "components.Settings.nodefault": "Nijedan defaultni server nije odabran!", "components.Settings.menuServices": "Servisi", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuNotifications": "Notifikacije", @@ -223,7 +218,6 @@ "components.MovieDetails.cast": "Postava", "components.MovieDetails.budget": "Budžet", "components.MovieDetails.MovieCast.fullcast": "Kompletna Glumačka Postava", - "components.Layout.alphawarning": "Ovo je softver u ALPHA stanju. Skoro sve je nestabilno. Molimo Vas prijavite sve probleme na Overseerr GitHub stranici!", "components.Layout.UserDropdown.signout": "Odjava", "components.Layout.Sidebar.users": "Korisnici", "components.Layout.Sidebar.settings": "Podešavanja", @@ -237,7 +231,6 @@ "components.Discover.recentlyAdded": "Nedavno Dodati", "components.Discover.populartv": "Popularne Serije", "components.Discover.popularmovies": "Popularni Filmovi", - "components.Discover.nopending": "Nema zahteva na čekanju", "components.Discover.discovertv": "Popularne Serije", "components.Discover.discovermovies": "Popunarni Filmov", "pages.errormessagewithcode": "{statusCode} - {error}" diff --git a/src/i18n/locale/sv.json b/src/i18n/locale/sv.json index 065295c7..b19dbd1a 100644 --- a/src/i18n/locale/sv.json +++ b/src/i18n/locale/sv.json @@ -13,21 +13,16 @@ "components.Settings.startscan": "Starta scanning", "components.Settings.ssl": "SSL", "components.Settings.sonarrsettings": "Sonarrinställningar", - "components.Settings.sonarrSettingsDescription": "Konfigurera din Sonarr-anslutning nedan. Du kan ha flera Sonarr-konfigurationer, men bara två kan vara aktiva som standard när som helst (en för standard HD och en för 4K). Administratörer kan åsidosätta servern som används för nya förfrågningar.", "components.Settings.servernamePlaceholder": "Plex Servernamn", "components.Settings.servername": "Servernamn", "components.Settings.radarrsettings": "Radarrinställningar", - "components.Settings.radarrSettingsDescription": "Konfigurera din Radarr-anslutning nedan. Du kan ha flera Radarr-konfigurationer, men bara två kan vara aktiva som standard (en för standard HD och en för 4K). Administratörer kan åsidosätta servern som används för nya förfrågningar.", "components.Settings.port": "Port", "components.Settings.plexsettingsDescription": "Konfigurera inställningarna för din Plex-server. Overseerr scannar din Plex-server för att se vilka media som är tillgängliga.", "components.Settings.plexsettings": "Plexinställningar", "components.Settings.plexlibrariesDescription": "Mediabiblioteken som Overseerr scannar för titlar. Konfigurera och spara dina Plex anslutningsinställningar och klicka sedan på knappen nedan utfall inga är listade.", "components.Settings.plexlibraries": "Plex Bibliotek", "components.Settings.notrunning": "Körs ej", - "components.Settings.notificationsettingsDescription": "Konfigurera globala notifikationsinställningar. Inställningarna nedanför gäller för alla tjänster.", "components.Settings.notificationsettings": "Notifikationsinställningar", - "components.Settings.nodefaultdescription": "Minst en server måste markeras som standard före du kan göra förfrågningar.", - "components.Settings.nodefault": "Ingen Standard-server", "components.Settings.menuServices": "Tjänster", "components.Settings.menuPlexSettings": "Plex", "components.Settings.menuNotifications": "Notifikationer", @@ -126,13 +121,13 @@ "components.Settings.Notifications.webhookUrlPlaceholder": "Serverinställningar → Integrationer → Webhooks", "components.Settings.Notifications.webhookUrl": "Webhook-URL", "components.Settings.Notifications.validationSmtpPortRequired": "Du måste ange ett giltigt port nummer", - "components.Settings.Notifications.validationSmtpHostRequired": "Du måste ange en värdnamn eller IP-adress", + "components.Settings.Notifications.validationSmtpHostRequired": "Du måste ange ett giltigt värdnamn eller IP-adress", "components.Settings.Notifications.smtpPort": "SMTP Port", "components.Settings.Notifications.smtpHost": "SMTP Server", "components.Settings.Notifications.enableSsl": "Aktivera SSL", "components.Settings.Notifications.emailsettingssaved": "Notiferingsinställningar för e-post sparade!", - "components.Settings.Notifications.discordsettingsfailed": "Notifieringsinställningar för Discord misslyckades att sparas.", - "components.Settings.Notifications.emailsettingsfailed": "Notifieringsinställningar för e-post misslyckades att sparas.", + "components.Settings.Notifications.discordsettingsfailed": "Notifieringsinställningar för Discord kunde inte sparas.", + "components.Settings.Notifications.emailsettingsfailed": "Notifieringsinställningar för e-post kunde inte sparas.", "components.Settings.Notifications.emailsender": "Avsändaradress", "components.Settings.Notifications.discordsettingssaved": "Notiferingsinställningar för Discord sparade!", "components.Settings.Notifications.authUser": "SMTP Användarnamn", @@ -168,13 +163,12 @@ "components.MovieDetails.originallanguage": "Ursprungligt Språk", "components.MovieDetails.manageModalTitle": "Hantera Film", "components.MovieDetails.manageModalRequests": "Förfrågningar", - "components.MovieDetails.manageModalNoRequests": "Inga förfrågningar", + "components.MovieDetails.manageModalNoRequests": "Inga förfrågningar.", "components.MovieDetails.manageModalClearMediaWarning": "Denna handling kan ej ångras och kommer att radera all data för denna film, inklusive alla förfrågningar. Om det här objektet finns i ditt Plex-bibliotek kommer media information att återskapas vid nästa inläsning.", "components.MovieDetails.manageModalClearMedia": "Rensa All Media Data", "components.MovieDetails.cast": "Roller", "components.MovieDetails.budget": "Budget", "components.MovieDetails.MovieCast.fullcast": "Rollista", - "components.Layout.alphawarning": "Detta är ALPHA-mjukvara. Funktioner kan bara trasiga och/eller instabila. Vänligen rapportera alla problem i GitHub!", "components.Layout.UserDropdown.signout": "Logga ut", "components.Layout.Sidebar.users": "Användare", "components.Layout.Sidebar.settings": "Inställningar", @@ -182,14 +176,13 @@ "components.Layout.Sidebar.dashboard": "Upptäck", "components.Layout.SearchInput.searchPlaceholder": "Sök Filmer & TV-Serier", "components.Layout.LanguagePicker.changelanguage": "Byt språk", - "components.Discover.upcomingmovies": "Kommande Filmer", - "components.Discover.upcoming": "Kommande Filmer", + "components.Discover.upcomingmovies": "Kommande filmer", + "components.Discover.upcoming": "Kommande filmer", "components.Discover.trending": "Trendande", "components.Discover.recentrequests": "Senaste förfrågningar", "components.Discover.recentlyAdded": "Nyligen tillagda", "components.Discover.populartv": "Populära TV-serier", "components.Discover.popularmovies": "Populära filmer", - "components.Discover.nopending": "Inga väntande förfrågningar", "components.Discover.discovertv": "Populära TV-serier", "components.Discover.discovermovies": "Populära filmer", "components.TvDetails.anime": "Anime", @@ -223,7 +216,7 @@ "components.UserList.plexuser": "Plex", "components.UserList.lastupdated": "Senast uppdaterad", "components.UserList.deleteuser": "Ta bort användare", - "components.UserList.deleteconfirm": "Är du säker på att du vill ta bort användaren? All data för användaren kommer att raderas.", + "components.UserList.deleteconfirm": "Är du säker på att du vill ta bort den här användaren? Alla förfrågningsdata tas bort permanent.", "components.UserList.created": "Skapad", "components.UserList.admin": "Administratör", "components.TvDetails.similar": "Liknande TV-serier", @@ -235,7 +228,7 @@ "components.TvDetails.network": "{networkCount, plural, one {Nätverk} other {Nätverk}}", "components.TvDetails.manageModalTitle": "Hantera TV-serier", "components.TvDetails.manageModalRequests": "Förfrågningar", - "components.TvDetails.manageModalNoRequests": "Inga förfrågningar", + "components.TvDetails.manageModalNoRequests": "Inga förfrågningar.", "components.TvDetails.manageModalClearMediaWarning": "* Denna handling går inte att ångra och raderar all media data för denna TV Serien, inklusive förfrågningar. Om objektet finns i ditt Plexbibliotek kommer mediainformationen att återskapas vid nästa skanning.", "components.TvDetails.manageModalClearMedia": "Rensa All Media Data", "components.TvDetails.cast": "Roller", @@ -248,28 +241,26 @@ "components.Settings.SettingsAbout.Releases.viewchangelog": "Visa ändringslogg", "components.Settings.SettingsAbout.Releases.versionChangelog": "Ändringslogg", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "De senaste ändringarna i utvecklings-grenen av Overseerr visas inte nedan. Se ändringshistoriken på GitHub för mer information.", - "components.Settings.SettingsAbout.Releases.runningDevelop": "Utvecklingsversion", "components.Settings.SettingsAbout.Releases.releases": "Versioner", "components.Settings.SettingsAbout.Releases.releasedataMissing": "Versionsdata saknas. Ligger GitHub nere?", "components.Settings.SettingsAbout.Releases.latestversion": "Senaste Versionen", "components.Settings.SettingsAbout.Releases.currentversion": "Aktuell Version", - "components.Settings.Notifications.testsent": "Test-notifikation skickad!", - "components.UserList.importfromplex": "Importera Användare från Plex", + "components.Settings.Notifications.testsent": "Telegram testmeddelande skickat!", + "components.UserList.importfromplex": "Importera användare från Plex", "components.UserList.importfromplexerror": "Någonting gick fel vid importen av användare från Plex.", "components.TvDetails.watchtrailer": "Kolla Trailer", "components.Settings.Notifications.allowselfsigned": "Tillåt Självsignerade Certifikat", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL", - "components.Settings.Notifications.NotificationsSlack.testsent": "Testnotifikation skickad!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Slack testmeddelande skickat!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Notiferingsinställningar för Slack sparade!", - "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Notifieringsinställningar för Slack misslyckades att sparas.", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Konfigurera Slack-notifikationer", + "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Notifieringsinställningar för Slack kunde inte sparas.", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Aktiverad", "components.MovieDetails.watchtrailer": "Kolla Trailer", "components.CollectionDetails.requestcollection": "Begär Kollektion", "components.CollectionDetails.overview": "Översikt", "components.CollectionDetails.numberofmovies": "Antal Filmer: {count}", "i18n.retry": "Försök igen", - "i18n.requested": "Begärda", + "i18n.requested": "Begärd", "i18n.request": "Begäran", "i18n.failed": "Misslyckades", "components.UserList.importedfromplex": "{userCount, plural, one {# new user} other {# new users}} importerade från Plex!", @@ -284,37 +275,31 @@ "components.Settings.Notifications.validationChatIdRequired": "Du måste ange ett giltigt chatt-ID", "components.Settings.Notifications.validationBotAPIRequired": "Du måste ange en bot-autentiseringstoken", "components.Settings.Notifications.telegramsettingssaved": "Notiferingsinställningar för Telegram sparade!", - "components.Settings.Notifications.telegramsettingsfailed": "Notifieringsinställningar för Telegram misslyckades att sparas.", + "components.Settings.Notifications.telegramsettingsfailed": "Notifieringsinställningar för Telegram kunde inte sparas.", "components.Settings.Notifications.ssldisabletip": "SSL bör inaktiveras på standard TLS-anslutningar (Port 587)", "components.Settings.Notifications.settinguptelegramDescription": "För att konfigurera Telegram-aviseringar måste du skapa en bot och hämta bot-API-nyckeln. Dessutom behöver du chatt-ID för chatten som du vill skicka meddelanden till. Du hittar detta genom att lägga till @get_id_bot i chatten och utfärda kommandot /my_id .", - "components.Settings.Notifications.settinguptelegram": "Konfigurera Telegram-notifikationer", "components.Settings.Notifications.senderName": "Avsändarens namn", - "components.Settings.Notifications.notificationtypes": "Notifikationstyper", "components.Settings.Notifications.chatId": "Chatt-ID", "components.Settings.Notifications.botAPI": "Bot-autentiseringstoken", "components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved": "Notiferingsinställningar för webhook sparade!", - "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Notifieringsinställningar för webhook misslyckades att sparas.", + "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Notifieringsinställningar för Webhook kunde inte sparas.", "components.Settings.Notifications.NotificationsWebhook.webhookUrl": "Webhook-URL", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "Du måste ange en giltig JSON Payload", - "components.Settings.Notifications.NotificationsWebhook.testsent": "Testmeddelande skickat!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "Webhook testmeddelande skickat!", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Lathund för variabler", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON har återställts!", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Återställ till Standard", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Notifikationstyper", "components.Settings.Notifications.NotificationsWebhook.customJson": "Ladda JSON", "components.Settings.Notifications.NotificationsWebhook.authheader": "Behörighetsrubrik", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "Aktiverad", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "För att konfigurera Slack-aviseringar måste du skapa en Inkommande webbhook -integration och ange webbhook-URL nedan.", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Notifikationstyper", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "Du måste ange en giltig användarnyckel", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "För att konfigurera Pushover-aviseringar måste du registrera ett program och ange API-token nedan. (Du kan använda en av våra officiella ikoner på GitHub .) Du behöver också din användarnyckel.", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "För att konfigurera Pushover-aviseringar måste du registrera ett program och ange API-token nedan. (Du kan använda en av våra Overseerr ikoner på GitHub .)", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "Du måste ange en giltig applikationstoken", - "components.Settings.Notifications.NotificationsPushover.userToken": "Användarnyckel", - "components.Settings.Notifications.NotificationsPushover.testsent": "Testmeddelande skickat!", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Konfigurera Pushover-notifikationer", + "components.Settings.Notifications.NotificationsPushover.userToken": "Användar- eller gruppnyckel", + "components.Settings.Notifications.NotificationsPushover.testsent": "Pushover testmeddelande skickat!", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Inställningar för Pushover-meddelanden sparade!", - "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Inställningar för pushover-meddelanden kunde inte sparas.", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Notifikationstyper", + "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Notifieringsinställningar för Pushover kunde inte sparas.", "components.Settings.Notifications.NotificationsPushover.agentenabled": "Aktiverad", "components.Settings.Notifications.NotificationsPushover.accessToken": "Applikation / API Token", "components.RequestModal.request4ktitle": "Begär {titel} i 4K", @@ -368,15 +353,10 @@ "components.PermissionEdit.managerequestsDescription": "Bevilja behörighet att hantera Overseerr-förfrågningar (inkluderar att godkänna och neka förfrågningar). Alla förfrågningar som görs av en användare med den här behörigheten kommer att godkännas.", "components.PermissionEdit.managerequests": "Hantera Förfrågningar", "components.PermissionEdit.adminDescription": "Fullständig administratörsbehörighet. Överskrider alla andra behörighetskontroller.", - "components.Settings.enablenotifications": "Aktivera Notifikationer", - "components.Settings.notificationsettingssaved": "Notifikationsinställningarna sparade!", - "components.Settings.notificationsettingsfailed": "Notifikationsinställningarna misslyckades med att sparas.", - "components.Settings.notificationAgentsSettings": "Notifikationstjänster", "components.PlexLoginButton.signinwithplex": "Logga in", "components.PlexLoginButton.signingin": "Loggar in…", "components.RequestModal.requesterror": "Någonting gick fel vid behandling av din begäran.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "Vi kunde inte automatiskt matcha din begäran. Var god välj den korrekta matchningen från listan nedanför.", - "components.RequestModal.SearchByNameModal.notvdbid": "Manuell Matchning Krävs", "components.RequestModal.SearchByNameModal.nosummary": "Ingen summering för denna titel hittades.", "i18n.experimental": "Experimentell", "components.Settings.hideAvailable": "Göm Tillgänglig Media", @@ -398,14 +378,13 @@ "components.UserList.validationpasswordminchars": "Lösenordet är för kort; det behöver innehålla minst 8 bokstäver", "components.UserList.usercreatedsuccess": "Användaren skapad!", "components.UserList.usercreatedfailed": "Någonting gick fel vid skapandet av användaren.", - "components.UserList.passwordinfodescription": "E-postnotifikationer behöver vara konfigurerade för att kunna automatiskt generera lösenord.", - "components.UserList.passwordinfo": "Lösenordsinformation", + "components.UserList.passwordinfodescription": "Aktivera e-postmeddelanden för att tillåta automatisk lösenordsgenerering.", "components.UserList.password": "Lösenord", "components.UserList.localuser": "Lokal Användare", "components.UserList.email": "E-postadress", "components.UserList.creating": "Skapar…", "components.UserList.createuser": "Skapa Användare", - "components.UserList.createlocaluser": "Skapa Lokal Användare", + "components.UserList.createlocaluser": "Skapa lokal användare", "components.UserList.create": "Skapa", "components.UserList.autogeneratepassword": "Generera lösenord automatiskt", "components.PersonDetails.crewmember": "Besättningsmedlem", @@ -469,7 +448,6 @@ "components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL:n får inte avslutas med ett slash", "components.PermissionEdit.viewrequestsDescription": "Bevilja behörighet att visa andra användares förfrågningar.", "components.PermissionEdit.viewrequests": "Visa Förfrågningar", - "components.AppDataWarning.dockerVolumeMissing": "Dockervolyms-montering saknas", "components.RequestModal.AdvancedRequester.requestas": "Begär Som", "components.Setup.setup": "Installationsguide", "components.Settings.validationApplicationTitle": "Du måste ange en applikationstitel", @@ -527,8 +505,7 @@ "components.Settings.toastPlexConnectingFailure": "Misslyckades med att ansluta till Plex.", "components.Settings.toastPlexConnecting": "Försöker ansluta till Plex…", "components.Settings.timeout": "Timeout", - "components.Settings.settingUpPlexDescription": "För att konfigurerar Plex, kan du antingen ställa in inställningarna manuellt eller välja en server som hämtats via plex.tv. Klicka på knappen till höger om rullgardinsmenyn för att kolla anslutningen och hämta tillgängliga servrar.", - "components.Settings.settingUpPlex": "Konfigurerar Plex", + "components.Settings.settingUpPlexDescription": "För att konfigurerar Plex, kan du antingen ställa in inställningarna manuellt eller välja en server som hämtats via plex.tv. Tryck på knappen till höger om rullgardinsmenyn för att hämta listan över tillgängliga servrar.", "components.Settings.serverpresetRefreshing": "Hämtar servrar…", "components.Settings.serverpresetPlaceholder": "Plex Server", "components.Settings.serverpresetManualMessage": "Manuell konfiguration", @@ -556,24 +533,20 @@ "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Något gick fel när du sparade lösenordet.", "components.UserProfile.UserSettings.UserPasswordChange.password": "Lösenord", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "Du har inte behörighet att ändra användarens lösenord.", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "Detta användarkonto har för närvarande inget lösenord specifikt för {applicationTitle}. Konfigurera ett lösenord nedan så att det här kontot kan logga in som en \"lokal användare\".", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "Inget lösenord inställt", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "Nytt lösenord", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Nuvarande lösenord", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Bekräfta lösenord", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Du måste ange ett giltigt ID för Telegram-chatt", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Du måste ange ett giltigt användar-ID för Discord", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "Du måste ange ett giltigt chatt-ID", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "Du måste ange ett giltigt användar-ID", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Notifieringsinställningar har sparats!", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Något gick fel när inställningarna sparades.", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "Starta en chatt, lägg till @get_id_bot och använd kommandot /my_id ", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Lägg till @get_id_bot i chatten", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegrem chatt-ID", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chatt-ID", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Skicka meddelanden utan ljud", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Skicka Telegram-meddelanden tyst", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Skicka tyst", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Aviseringsinställningar", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Aktivera aviseringar", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": " ID-nummer för ditt Discord-användarkonto", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord-ID", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": " ID-nummer för ditt användarkonto", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Användar-ID", "components.UserProfile.UserSettings.UserGeneralSettings.user": "Användare", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Inställningarna har sparats!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Något gick fel när inställningarna sparades.", @@ -597,7 +570,7 @@ "components.UserList.sortUpdated": "Senast uppdaterad", "components.UserList.sortRequests": "Antal förfrågningar", "components.UserList.sortDisplayName": "Visningsnamn", - "components.UserList.sortCreated": "Skapelsedagen", + "components.UserList.sortCreated": "Skapad", "components.UserList.owner": "Ägare", "components.UserList.edituser": "Redigera användarebehörigheter", "components.UserList.accounttype": "Kontotyp", @@ -610,7 +583,7 @@ "components.Settings.region": "Upptäck Region", "components.Settings.originallanguageTip": "Filtrera innehåll efter originalspråk", "components.Settings.originallanguage": "Upptäck språk", - "components.Settings.notificationAgentSettingsDescription": "Välj vilka typer av aviseringar som ska skickas och vilka aviseringsagenter som ska användas.", + "components.Settings.notificationAgentSettingsDescription": "Konfigurera och aktivera aviseringsagenter.", "components.Settings.menuUsers": "Användare", "components.Settings.email": "E-post", "components.Settings.SonarrModal.validationLanguageProfileRequired": "Du måste välja en språkprofil", @@ -638,20 +611,17 @@ "components.Settings.Notifications.sendSilently": "Skicka tyst", "components.Settings.Notifications.emailNotificationTypesAlertDescriptionPt2": " Medie godkänd, Media nekad och Media tillgängligt e-postmeddelanden skickas till användaren som skickade begäran.", "components.Settings.Notifications.emailNotificationTypesAlertDescription": " E-postmeddelanden , Automatiskt godkänd media och Media misslyckades skickas till alla användare med behörigheten Hantera begäranden . .", - "components.Settings.Notifications.emailNotificationTypesAlert": "Mottagare av e-postmeddelanden", "components.Settings.Notifications.botUsername": "Bot-användarnamn", "components.Settings.Notifications.botAvatarUrl": "Bot Avatar URL", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "Du måste ange en åtkomsttoken", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "Testnotifikation skickad!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "För att konfigurera Pushbullet-aviseringar måste du skapa en åtkomsttoken och ange den nedan.", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Ställ in Pushbullet-meddelanden", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Pushbullet testmeddelande skickat!", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "För att konfigurera Pushbullet-aviseringar måste du skapa en åtkomsttoken .", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Meddelandeinställningar för Pushbullet sparades!", - "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Meddelandeinställningarna för Pushbullet kunde inte sparas.", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Notifikationstyper", + "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Notifieringsinställningar för Pushover kunde inte sparas.", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "Aktivera agent", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "Åtkomsttoken", "components.RequestModal.AdvancedRequester.languageprofile": "Språkprofil", - "components.RequestList.RequestItem.requested": "Begärda", + "components.RequestList.RequestItem.requested": "Begärd", "components.RequestList.RequestItem.modifieduserdate": "{date} av{user}", "components.RequestList.RequestItem.modified": "Modifierad", "components.RequestBlock.requestoverrides": "Begär åsidosättningar", @@ -685,16 +655,14 @@ "components.Discover.TvGenreList.seriesgenres": "Seriegenrer", "components.Discover.TvGenreSlider.tvgenres": "Seriegenrer", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})", - "components.UserProfile.norequests": "Inga förfrågningar", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Kryptera e-postmeddelanden", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP Publik nyckel", + "components.UserProfile.norequests": "Inga förfrågningar.", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minuter", "components.TvDetails.episodeRuntime": "Avsnittets speltid", "components.Settings.partialRequestsEnabled": "Tillåt begäran av ofullständig serie", - "components.Settings.Notifications.pgpPrivateKeyTip": "Signera krypterade e-postmeddelanden (PGP-lösenord krävs)", - "components.Settings.Notifications.pgpPrivateKey": "PGP Privat nyckel", - "components.Settings.Notifications.pgpPasswordTip": "Signera krypterade e-postmeddelanden (PGP privat nyckel krävs)", - "components.Settings.Notifications.pgpPassword": "PGP Lösenord", + "components.Settings.Notifications.pgpPrivateKeyTip": "Signera krypterade e-postmeddelanden med OpenPGP ", + "components.Settings.Notifications.pgpPrivateKey": "PGP Privat nyckel", + "components.Settings.Notifications.pgpPasswordTip": "Signera krypterade e-postmeddelanden med OpenPGP ", + "components.Settings.Notifications.pgpPassword": "PGP Lösenord", "components.RequestModal.requestall": "Begär alla säsonger", "components.RequestModal.alreadyrequested": "Redan begärd", "components.UserProfile.UserSettings.UserGeneralSettings.general": "Allmänna", @@ -706,7 +674,6 @@ "i18n.usersettings": "Användarinställningar", "i18n.settings": "Inställningar", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Något gick fel när lösenordet sparades. Har ditt nuvarande lösenord skrivits in korrekt?", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Ditt konto har för närvarande inget lösenord specifikt för {applicationTitle}. Konfigurera ett lösenord nedan för att aktivera inloggning som en \"lokal användare\" med din e-postadress.", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notifieringar", "components.Settings.services": "Tjänster", "components.Settings.plex": "Plex", @@ -753,7 +720,6 @@ "components.QuotaSelector.tvRequestLimit": "{quotaLimit} säsong(er) per {quotaDays} dag(ar)", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} film(er) per {quotaDays} dag(ar)", "i18n.view": "Visa", - "i18n.unauthorized": "Obehörig", "i18n.tvshow": "Serier", "i18n.testing": "Testar…", "i18n.test": "Test", @@ -792,5 +758,64 @@ "components.TvDetails.originaltitle": "Originaltitel", "components.MovieDetails.originaltitle": "Originaltitle", "components.LanguageSelector.originalLanguageDefault": "Alla språk", - "components.LanguageSelector.languageServerDefault": "Standard ({language})" + "components.LanguageSelector.languageServerDefault": "Standard ({language})", + "components.Settings.SonarrModal.testFirstTags": "Testa anslutningen för att ladda taggar", + "components.Settings.SonarrModal.tags": "Taggar", + "components.Settings.SonarrModal.selecttags": "Välj taggar", + "components.Settings.SonarrModal.notagoptions": "Inga taggar.", + "components.Settings.SonarrModal.loadingTags": "Laddar taggar…", + "components.Settings.SonarrModal.edit4ksonarr": "Redigera 4K Sonarr-server", + "components.Settings.SonarrModal.default4kserver": "Standard 4K server", + "components.Settings.SonarrModal.create4ksonarr": "Lägg till ny 4K Sonarr-server", + "components.Settings.SonarrModal.animeTags": "Anime taggar", + "components.Settings.RadarrModal.testFirstTags": "Testa anslutningen för att ladda taggar", + "components.Settings.RadarrModal.tags": "Taggar", + "components.Settings.RadarrModal.selecttags": "Välj taggar", + "components.Settings.RadarrModal.create4kradarr": "Lägg till ny 4K Radarr-server", + "components.Settings.RadarrModal.notagoptions": "Inga taggar.", + "components.Settings.RadarrModal.edit4kradarr": "Redigera 4K Radarr-server", + "components.Settings.RadarrModal.default4kserver": "Standard 4K server", + "components.RequestModal.AdvancedRequester.tags": "Taggar", + "components.RequestModal.AdvancedRequester.selecttags": "Välj taggar", + "components.RequestModal.AdvancedRequester.notagoptions": "Inga taggar.", + "components.Settings.RadarrModal.loadingTags": "Laddar taggar…", + "components.RequestList.RequestItem.mediaerror": "Den tillhörande titeln för den här begäran är inte längre tillgänglig.", + "components.RequestList.RequestItem.deleterequest": "Ta bort begäran", + "components.RequestCard.mediaerror": "Den tillhörande titeln för denna begäran är inte längre tillgänglig.", + "components.RequestCard.deleterequest": "Ta bort begäran", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Notifieringsinställningar för Discord kunde inte sparas.", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "Du måste ange en giltig offentlig PGP-nyckel", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Notiferingsinställningar för Telegram sparade!", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Notifieringsinställningar för Telegram kunde inte sparas.", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "Kryptera e-postmeddelanden med OpenPGP", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "Offentlig PGP-nyckel", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "Aktivera aviseringar", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "Aktivera aviseringar", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "Aktivera omnämningar", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "Notiferingsinställningar för e-post sparade!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "Notifieringsinställningar för e-post kunde inte sparas.", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "E-post", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Notiferingsinställningar för Discord sparade!", + "components.Settings.Notifications.validationPgpPrivateKey": "Du måste ange en giltig privat PGP-nyckel om ett PGP-lösenord anges", + "components.Settings.Notifications.validationPgpPassword": "Du måste ange ett PGP-lösenord om en privat PGP-nyckel anges", + "components.Settings.Notifications.botUsernameTip": "Låt användare starta en chatt med botten och konfigurera sina egna personliga aviseringar", + "components.RequestModal.pendingapproval": "Din begäran väntar på godkännande.", + "components.RequestList.RequestItem.cancelRequest": "Avbryt begäran", + "components.NotificationTypeSelector.notificationTypes": "Notifikationstyper", + "components.Discover.noRequests": "Inga förfrågningar.", + "components.Layout.VersionStatus.streamstable": "Overseerr Stabil", + "components.Layout.VersionStatus.streamdevelop": "Overseerr Utväckling", + "components.Layout.VersionStatus.outofdate": "Föråldrad", + "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {ändring} other {ändringar}} efter", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Ditt konto har för närvarande inget lösenord. Konfigurera ett lösenord nedan för att aktivera inloggning som en \"lokal användare\" med din e-postadress.", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "Det här användarkontot har för närvarande inget lösenord. Konfigurera ett lösenord nedan så att det här kontot kan logga in som en \"lokal användare\".", + "components.Settings.serviceSettingsDescription": "Konfigurera din server {serverType} nedan. Du kan ansluta flera {serverType} servrar, men bara två av dem kan markeras som standard (en icke-4K och en 4K). Administratörer kan åsidosätta servern som används för att behandla nya förfrågningar innan godkännande.", + "components.Settings.noDefaultServer": "Minst en {serverType} server måste markeras som standard för att {mediaType} -förfrågningar ska kunna behandlas.", + "components.Settings.noDefaultNon4kServer": "Om du bara har en enda {serverType} server för både icke-4K- och 4K-innehåll (eller om du bara laddar ner 4K-innehåll) bör din {serverType} server INTE betecknas som en 4K-server.", + "components.Settings.mediaTypeSeries": "serier", + "components.Settings.mediaTypeMovie": "film", + "components.Settings.SettingsAbout.uptodate": "Aktuell", + "components.Settings.SettingsAbout.outofdate": "Föråldrad", + "components.UserList.autogeneratepasswordTip": "Skicka ett servergenererat lösenord via e-post till användaren", + "components.Layout.betawarning": "Detta är BETA-programvara. Funktioner kan vara trasiga och/eller instabila. Rapportera eventuella problem på GitHub!" } diff --git a/src/i18n/locale/zh_Hant.json b/src/i18n/locale/zh_Hant.json index f28349bb..07e6c654 100644 --- a/src/i18n/locale/zh_Hant.json +++ b/src/i18n/locale/zh_Hant.json @@ -6,10 +6,10 @@ "components.Settings.SonarrModal.apiKey": "應用程式密鑰", "components.Settings.apikey": "應用程式密鑰", "components.Settings.RadarrModal.apiKey": "應用程式密鑰", - "components.Settings.Notifications.testsent": "測試通知已發送!", - "components.Settings.Notifications.NotificationsSlack.testsent": "測試通知已發送!", - "components.Settings.Notifications.NotificationsPushover.testsent": "測試通知已發送!", - "components.Settings.Notifications.NotificationsWebhook.testsent": "測試通知已發送!", + "components.Settings.Notifications.testsent": "Telegram 測試通知已發送!", + "components.Settings.Notifications.NotificationsSlack.testsent": "Slack 測試通知已發送!", + "components.Settings.Notifications.NotificationsPushover.testsent": "Pushover 測試通知已發送!", + "components.Settings.Notifications.NotificationsWebhook.testsent": "網絡鉤手測試通知已發送!", "components.Settings.Notifications.senderName": "發件人姓名", "components.Settings.Notifications.enableSsl": "啟用安全通訊協定(SSL)", "components.Settings.Notifications.emailsender": "發件人電子郵件地址", @@ -17,8 +17,6 @@ "components.Settings.Notifications.authPass": "SMTP 密碼", "components.Settings.Notifications.NotificationsWebhook.agentenabled": "啟用", "components.Settings.Notifications.agentenabled": "啟用", - "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "通知類型", - "components.Settings.Notifications.notificationtypes": "通知類型", "components.Settings.Notifications.NotificationsSlack.agentenabled": "啟用", "components.Settings.Notifications.NotificationsPushover.agentenabled": "啟用", "components.Settings.Notifications.validationSmtpPortRequired": "必須輸入有效通訊埠", @@ -28,7 +26,6 @@ "i18n.partiallyavailable": "部分可觀看", "i18n.unavailable": "不可觀看", "components.StatusChacker.newversionavailable": "軟體更新", - "components.Layout.alphawarning": "這是預覽版軟體,所以可能會不穩定或被破壞。請向 GitHub 報告問題!", "components.StatusBadge.status4k": "4K 版 {status}", "components.Setup.tip": "提示", "components.Setup.welcome": "歡迎來到 Overseerr", @@ -70,9 +67,9 @@ "i18n.tvshows": "電視節目", "pages.oops": "哎呀", "components.TvDetails.manageModalTitle": "電視節目管理", - "components.MovieDetails.manageModalNoRequests": "無請求", + "components.MovieDetails.manageModalNoRequests": "沒有請求。", "components.TvDetails.manageModalRequests": "請求", - "components.TvDetails.manageModalNoRequests": "無請求", + "components.TvDetails.manageModalNoRequests": "沒有請求。", "components.TvDetails.manageModalClearMedia": "清除所有儲存資料", "components.TvDetails.firstAirDate": "原始播出日期", "i18n.delete": "刪除", @@ -92,8 +89,6 @@ "components.Settings.RadarrModal.loadingrootfolders": "載入中…", "components.Settings.RadarrModal.loadingprofiles": "載入中…", "components.Settings.toastSettingsSuccess": "設置保存成功!", - "components.Settings.Notifications.NotificationsSlack.notificationtypes": "通知類型", - "components.Settings.Notifications.NotificationsPushover.notificationtypes": "通知類型", "components.Search.searchresults": "搜索結果", "components.RequestModal.seasonnumber": "第 {number} 季", "components.RequestModal.season": "季數", @@ -162,7 +157,6 @@ "components.Discover.recentrequests": "最新請求", "components.Discover.populartv": "熱門電視節目", "components.Discover.popularmovies": "熱門電影", - "components.Discover.nopending": "沒有待處理的請求", "components.Discover.discovertv": "熱門電視節目", "components.Discover.discovermovies": "熱門電影", "components.CollectionDetails.requestswillbecreated": "為以下的電影提交請求:", @@ -214,7 +208,6 @@ "components.Settings.RadarrModal.testFirstRootFolders": "請先測試連線", "components.Settings.RadarrModal.testFirstQualityProfiles": "請先測試連線", "components.Settings.SonarrModal.defaultserver": "默認伺服器", - "components.Settings.nodefault": "沒有默認伺服器", "components.Settings.deleteserverconfirm": "確定要刪除這個伺服器嗎?", "components.Settings.addradarr": "添加 Radarr 伺服器", "components.Settings.addsonarr": "添加 Sonarr 伺服器", @@ -236,9 +229,6 @@ "components.Settings.Notifications.emailsettingssaved": "電子郵件通知設置保存成功!", "components.Settings.Notifications.chatId": "聊天室 ID", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover 通知設置保存失敗。", - "components.Settings.Notifications.settinguptelegram": "Telegram 通知設定", - "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Pushover 通知設定", - "components.Settings.Notifications.NotificationsSlack.settingupslack": "Slack 通知設定", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack 通知設置保存失敗。", "components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "網絡鉤手通知設置保存失敗。", "components.Settings.Notifications.discordsettingsfailed": "Discord 通知設置保存失敗。", @@ -255,10 +245,9 @@ "components.Settings.toastApiKeyFailure": "生成應用程式密鑰出了點問題。", "components.Settings.SonarrModal.apiKeyPlaceholder": "您的 Sonarr 應用程式密鑰", "components.Settings.toastSettingsFailure": "保存設置中出了點問題。", - "components.UserList.deleteconfirm": "確定要刪除這個用戶嗎?由這個用戶的所有儲存資料將被清除。", + "components.UserList.deleteconfirm": "確定要刪除這個用戶嗎?此用戶的所有儲存資料將被清除。", "components.Settings.SettingsAbout.Releases.releasedataMissing": "無法獲取軟體版本資料。GitHub 崩潰了嗎?", "components.UserList.passwordinfodescription": "啟用電子郵件通知才能自動生成密碼。", - "components.UserList.passwordinfo": "密碼生成", "components.Settings.Notifications.validationBotAPIRequired": "必須輸入 bot 機器人應用程式密鑰", "components.Settings.Notifications.botAPI": "Bot 機器人應用程式密鑰", "components.Settings.menuServices": "伺服器", @@ -269,7 +258,7 @@ "components.Settings.port": "通訊埠", "components.Settings.SonarrModal.port": "通訊埠", "components.Settings.RadarrModal.port": "通訊埠", - "components.Settings.Notifications.NotificationsPushover.userToken": "用戶令牌", + "components.Settings.Notifications.NotificationsPushover.userToken": "用戶或群組令牌", "components.Settings.Notifications.NotificationsPushover.accessToken": "應用程式 API 令牌", "components.Settings.menuNotifications": "通知", "components.Settings.menuLogs": "日誌", @@ -286,7 +275,6 @@ "components.RequestModal.pendingrequest": "{title} 的請求", "components.RequestModal.extras": "特輯", "components.Settings.SettingsAbout.Releases.versionChangelog": "變更日誌", - "components.Settings.SettingsAbout.Releases.runningDevelop": "開發版本", "components.Settings.SettingsAbout.Releases.releases": "軟體版本", "components.Settings.plexsettings": "Plex 設置", "components.RequestModal.selectseason": "季數選擇", @@ -381,10 +369,8 @@ "components.Settings.SonarrModal.externalUrlPlaceholder": "Sonarr 伺服器的外部網址(URL)", "components.Settings.RadarrModal.externalUrlPlaceholder": "Radarr 伺服器的外部網址(URL)", "components.Settings.SonarrModal.preventSearch": "禁用自動搜索", - "components.Settings.notificationsettingssaved": "通知設置保存成功!", "components.UserList.userssaved": "用戶權限保存成功!", "components.Settings.hideAvailable": "隱藏可觀看的電影和電視節目", - "components.RequestModal.SearchByNameModal.notvdbid": "必須手動配對", "components.Settings.RadarrModal.preventSearch": "禁用自動搜索", "components.Settings.SonarrModal.externalUrl": "外部網址", "components.Settings.RadarrModal.externalUrl": "外部網址(URL)", @@ -398,14 +384,12 @@ "components.MovieDetails.mark4kavailable": "標記為 4K 可觀看", "components.MovieDetails.markavailable": "標記為可觀看", "components.TvDetails.downloadstatus": "下載狀態", - "components.Settings.settingUpPlex": "配置您的 Plex 伺服器", "components.Settings.RadarrModal.syncEnabled": "啟用掃描", "i18n.experimental": "實驗性", "components.UserList.bulkedit": "批量編輯", "i18n.edit": "編輯", "components.Settings.timeout": "超時", "components.Settings.serverpresetManualMessage": "手動設定", - "components.Settings.enablenotifications": "啟用通知", "components.NotificationTypeSelector.mediadeclined": "請求拒絕", "components.TvDetails.playonplex": "在 Plex 上觀看", "components.TvDetails.play4konplex": "在 Plex 上觀看 4K 版", @@ -453,7 +437,6 @@ "components.Settings.SettingsAbout.preferredmethod": "首選", "i18n.advanced": "進階", "components.Settings.copied": "應用程式密鑰已複製到剪貼板。", - "components.Settings.notificationAgentsSettings": "發送通知代理服務", "components.Settings.serverpresetLoad": "請點右邊的按鈕", "components.Settings.toastPlexRefreshSuccess": "獲取 Plex 伺服器列表成功!", "components.Settings.toastPlexRefreshFailure": "獲取 Plex 伺服器列表失敗。", @@ -463,14 +446,12 @@ "components.TvDetails.manageModalClearMediaWarning": "*這電視節目的所有儲存資料將被永久刪除(包括用戶提交的請求)。如果節目存在於您的 Plex 伺服器,資料會在媒體庫掃描時重新建立。", "components.MovieDetails.manageModalClearMediaWarning": "*這電影的所有儲存資料將被永久刪除(包括用戶提交的請求)。如果電影存在於您的 Plex 伺服器,資料會在媒體庫掃描時重新建立。", "components.TvDetails.allseasonsmarkedavailable": "*每季將被標記為可觀看。", - "components.Settings.notificationsettingsfailed": "通知設置保存失敗。", "components.Settings.csrfProtectionHoverTip": "除非您了解此功能,請勿啟用它!", "components.UserList.users": "用戶", "components.Settings.applicationTitle": "應用程序名", "components.Search.search": "搜索", "components.Setup.setup": "配置", "components.Discover.discover": "探索", - "components.AppDataWarning.dockerVolumeMissing": "無法訪問 Docker 繫結掛載", "components.AppDataWarning.dockerVolumeMissingDescription": "必須使用繫結掛載(bind mount)指定某個宿主機器的資料夾跟容器內的 {appDataPath} 資料夾連通,才能保存 Overseerr 的配置和數據。", "components.RequestModal.AdvancedRequester.requestas": "請求者", "components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "必須刪除結尾斜線", @@ -553,13 +534,11 @@ "components.UserProfile.UserSettings.UserPasswordChange.password": "密碼設置", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "確認密碼", "components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "通知設置", - "components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "啟用通知", "components.UserList.edituser": "編輯用戶權限", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Pushbullet 通知設置保存失敗。", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet 通知設置保存成功!", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Pushbullet 通知設定", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "必須輸入 API 令牌", - "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord 用戶 ID", + "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "用戶 ID", "components.UserProfile.ProfileHeader.profile": "個人檔案", "components.UserProfile.ProfileHeader.settings": "用戶設定", "components.UserProfile.UserSettings.UserGeneralSettings.displayName": "用戶名", @@ -570,32 +549,28 @@ "components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "保存設置中出了點問題。", "components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "保存設置中出了點問題。", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "保存設置中出了點問題。", - "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "通知類型", "components.Settings.Notifications.NotificationsPushbullet.agentEnabled": "啟用", "components.Settings.Notifications.NotificationsPushbullet.accessToken": "API 令牌", - "components.Settings.Notifications.NotificationsPushbullet.testSent": "測試通知已發送!", + "components.Settings.Notifications.NotificationsPushbullet.testSent": "Pushbullet 測試通知已發送!", "components.Layout.UserDropdown.settings": "用戶設定", "components.Layout.UserDropdown.myprofile": "個人檔案", "components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "密碼必須匹配", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "密碼未設置", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "當前的密碼", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "新密碼", "components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "必須輸入當前的密碼", "components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "必須輸入新密碼", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "密碼設置成功!", "components.RequestModal.SearchByNameModal.nosummary": "沒有概要。", - "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "必須輸入有效 Discord 用戶 ID", - "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "您的 Discord 用戶身分證號碼", + "components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "必須輸入有效用戶 ID", + "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "您的用戶身分證號碼", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "重設密碼中出了點問題。", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "此用戶沒有 {applicationTitle} 專用的密碼。設置密碼以允許使用本地用戶登錄。", - "components.Settings.nodefaultdescription": "您必須至少設置一個默認伺服器,用戶提交的請求才能被滿足。", "components.RequestModal.SearchByNameModal.notvdbiddescription": "無法自動配對您的請求。請從以下列表中選擇正確的媒體項。", "components.CollectionDetails.requestswillbecreated4k": "為以下的電影提交 4K 請求:", "components.CollectionDetails.requestcollection4k": "提交 4K 系列請求", "components.Settings.SettingsAbout.Releases.runningDevelopMessage": "develop 分支的變更日誌不會顯示在以下。請直接到 GitHub 查看變更日誌。", "components.Settings.Notifications.settinguptelegramDescription": "要設置 Telegram 通知,必須先建立一個 「bot」 機器人以及把 @get_id_bot 加到聊天室,然後在以下輸入機器人應用程式密鑰和聊天室的 ID 號(可在聊天室裡發出 /my_id 命令查找聊天室 ID)。", - "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "要設置 Pushbullet 通知,必須先獲取 API 令牌,然後在下面輸入。", - "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "要設置 Pushover 通知,必須先建立一個應用程式,然後在以下輸入生成的 API 令牌和您的用戶密鑰。(添加應用時可以使用 Overseerr 的官方圖標。)", + "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "要設置 Pushbullet 通知,必須先獲取 API 令牌。", + "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "要設置 Pushover 通知,必須先建立一個應用程式。(可以使用 Overseerr 的官方圖標。)", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "要設置 Slack 通知,必須先建立一個 「incoming webhook」,然後在以下輸入生成的網絡鉤手網址。", "components.Settings.trustProxyTip": "使用代理伺服器時,允許 Overseerr 探明客戶端 IP 位址(Overseerr 必須重新啟動)", "components.Settings.csrfProtectionTip": "設置外部訪問權限為只讀(Overseerr 必須重新啟動)", @@ -609,9 +584,7 @@ "components.Discover.upcomingtv": "即將上映的電視節目", "components.Settings.webhook": "網絡鉤手", "components.Settings.email": "電子郵件", - "components.Settings.Notifications.emailNotificationTypesAlert": "電子郵件通知收件人", "components.Settings.generalsettingsDescription": "Overseerr 的全局和默認設置。", - "components.Settings.notificationsettingsDescription": "關於通知的全局設置。", "components.Settings.notificationAgentSettingsDescription": "設置通知類型和代理服務。", "components.Settings.Notifications.emailNotificationTypesAlertDescription": "「請求提交」、「請求自動批准」、「請求失敗」這幾種通知類型,將發送通知給所有具有「請求管理」權限的用戶。", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "以地區可用性篩選結果", @@ -621,10 +594,8 @@ "components.Settings.SettingsJobsCache.jobsDescription": "Overseerr 將定時運行以下的維護任務。手動執行工作不會影響它正常的時間表。", "components.Settings.plexsettingsDescription": "關於 Plex 伺服器的設置。Overseerr 將定時執行媒體庫掃描。", "components.Settings.manualscanDescription": "在正常情況下,Overseerr 會每24小時掃描您的 Plex 媒體庫。最新添加的媒體將更頻繁掃描。設置新的 Plex 伺服器時,我們建議您執行一次手動掃描!", - "components.RegionSelector.regionServerDefault": "默認({region})", - "components.Settings.settingUpPlexDescription": "您可以手動輸入您的 Plex 伺服器資料,或從 plex.tv 返回的設置做選擇以及自動配置。請點下拉式選單右邊的按鈕測試連線。", - "components.Settings.sonarrSettingsDescription": "關於 Sonarr 伺服器的設置。伺服器數沒有最大值限制,但您只能指定兩個伺服器為默認(一個非 4K、一個 4K)。", - "components.Settings.radarrSettingsDescription": "關於 Radarr 伺服器的設置。伺服器數沒有最大值限制,但您只能指定兩個伺服器為默認(一個非 4K、一個 4K)。", + "components.RegionSelector.regionServerDefault": "默認設置({region})", + "components.Settings.settingUpPlexDescription": "您可以手動輸入您的 Plex 伺服器資料,或從 plex.tv 返回的設置做選擇以及自動配置。請點下拉式選單右邊的按鈕獲取伺服器列表。", "components.Settings.plexlibrariesDescription": "Overseerr 將掃描的媒體庫。", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "您無權設置此用戶的密碼。", "components.UserProfile.UserSettings.UserGeneralSettings.user": "用戶", @@ -643,12 +614,11 @@ "components.Discover.DiscoverStudio.studioMovies": "{studio} 電影", "components.Discover.DiscoverMovieGenre.genreMovies": "{genre}電影", "i18n.loading": "載入中…", - "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "必須輸入 Telegram 聊天室 ID", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram 聊天室 ID", - "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "無聲 Telegram 通知", + "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "必須輸入聊天室 ID", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "聊天室 ID", + "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "無聲通知", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "發送沒有聲音警報的通知", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "先建立一個聊天室以及把 @get_id_bot 加到聊天室,然後在聊天室裡發出 /my_id 命令", - "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "把 @get_id_bot 加到聊天室", "components.Settings.Notifications.botUsername": "Bot 機器人名", "components.Discover.NetworkSlider.networks": "電視網", "components.Discover.StudioSlider.studios": "製作公司", @@ -680,13 +650,11 @@ "components.NotificationTypeSelector.mediaAutoApproved": "請求自動批准", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "您不能編輯自己的權限。", "components.UserProfile.UserSettings.unauthorizedDescription": "您無權編輯此用戶的設置。", - "components.Settings.Notifications.pgpPrivateKeyTip": "啟用電子郵件加密與簽章(PGP 解密密碼也必須輸入)", - "components.Settings.Notifications.pgpPasswordTip": "啟用電子郵件加密與簽章(PGP 私鑰也必須輸入)", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "啟用電子郵件加密", - "components.UserProfile.norequests": "無請求", - "components.Settings.Notifications.pgpPassword": "PGP 解密密碼", - "components.Settings.Notifications.pgpPrivateKey": "PGP 私鑰", - "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "PGP 公鑰", + "components.Settings.Notifications.pgpPrivateKeyTip": "使用 OpenPGP 電子郵件加密與簽章", + "components.Settings.Notifications.pgpPasswordTip": "使用 OpenPGP 電子郵件加密與簽章", + "components.UserProfile.norequests": "沒有請求。", + "components.Settings.Notifications.pgpPassword": "PGP 解密密碼", + "components.Settings.Notifications.pgpPrivateKey": "PGP 私鑰", "components.TvDetails.episodeRuntime": "劇集片長", "components.TvDetails.episodeRuntimeMinutes": "{runtime} 分鐘", "components.RequestModal.AdvancedRequester.folder": "{path}({space})", @@ -708,7 +676,6 @@ "components.Settings.SettingsLogs.level": "等級", "components.Settings.SettingsLogs.logs": "日誌", "components.Settings.SettingsLogs.showall": "查看所有日誌", - "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "您的帳戶目前沒有 {applicationTitle} 專用的密碼。設置密碼以允許使用電子郵件地址登錄。", "components.UserProfile.UserSettings.UserNotificationSettings.notifications": "通知", "components.Settings.SettingsUsers.users": "用戶", "pages.errormessagewithcode": "{statusCode}-{error}", @@ -765,7 +732,6 @@ "components.UserProfile.totalrequests": "請求總數", "components.UserProfile.seriesrequest": "電視節目請求", "i18n.view": "檢視", - "i18n.unauthorized": "未經授權", "i18n.tvshow": "電視節目", "i18n.testing": "測試中…", "i18n.test": "測試", @@ -791,6 +757,65 @@ "components.MovieDetails.originaltitle": "原始標題", "components.RequestModal.QuotaDisplay.quotaLinkUser": "訪問此用戶的個人資料頁面以查看用戶的請求限制 。", "components.RequestModal.QuotaDisplay.quotaLink": "訪問您的個人資料頁面以查看您的請求限制 。", - "components.LanguageSelector.languageServerDefault": "默認({language})", - "components.LanguageSelector.originalLanguageDefault": "所有語言" + "components.LanguageSelector.languageServerDefault": "默認設置({language})", + "components.LanguageSelector.originalLanguageDefault": "所有語言", + "components.RequestModal.AdvancedRequester.selecttags": "標籤設定", + "components.Settings.SonarrModal.selecttags": "標籤設定", + "components.Settings.RadarrModal.selecttags": "標籤設定", + "components.Settings.SonarrModal.notagoptions": "沒有標籤。", + "components.Settings.RadarrModal.notagoptions": "沒有標籤。", + "components.RequestModal.AdvancedRequester.notagoptions": "沒有標籤。", + "components.Settings.SonarrModal.edit4ksonarr": "編輯 4K Sonarr 伺服器", + "components.Settings.RadarrModal.edit4kradarr": "編輯 4K Radarr 伺服器", + "components.Settings.RadarrModal.create4kradarr": "添加 4K Radarr 伺服器", + "components.Settings.SonarrModal.create4ksonarr": "添加 4K Sonarr 伺服器", + "components.Settings.SonarrModal.default4kserver": "默認 4K 伺服器", + "components.Settings.RadarrModal.default4kserver": "默認 4K 伺服器", + "components.Settings.SonarrModal.testFirstTags": "請先測試連線", + "components.Settings.RadarrModal.testFirstTags": "請先測試連線", + "components.Settings.SonarrModal.loadingTags": "載入中…", + "components.Settings.SonarrModal.animeTags": "動漫標籤", + "components.Settings.SonarrModal.tags": "標籤", + "components.Settings.RadarrModal.tags": "標籤", + "components.RequestModal.AdvancedRequester.tags": "標籤", + "components.Settings.RadarrModal.loadingTags": "載入中…", + "components.RequestList.RequestItem.mediaerror": "找不到此請求的媒體項目。", + "components.RequestCard.mediaerror": "找不到此請求的媒體項目。", + "components.RequestList.RequestItem.deleterequest": "刪除請求", + "components.RequestCard.deleterequest": "刪除請求", + "components.Settings.Notifications.botUsernameTip": "允許用戶把機器人加到自己的聊天室以及設定自己的通知", + "components.RequestModal.pendingapproval": "您的請求正在等待管理員批准。", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram 通知設置保存失敗。", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed": "電子郵件通知設置保存失敗。", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Discord 通知設置保存失敗。", + "components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Telegram 通知設置保存成功!", + "components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved": "電子郵件通知設置保存成功!", + "components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved": "Discord 通知設置保存成功!", + "components.UserProfile.UserSettings.UserNotificationSettings.enableDiscord": "啟用提及", + "components.UserProfile.UserSettings.UserNotificationSettings.enableTelegram": "啟用通知", + "components.UserProfile.UserSettings.UserNotificationSettings.enableEmail": "啟用通知", + "components.UserProfile.UserSettings.UserNotificationSettings.email": "電子郵件", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip": "使用 OpenPGP 電子郵件加密", + "components.Settings.Notifications.validationPgpPassword": "必須輸入 PGP 解密密碼", + "components.Settings.Notifications.validationPgpPrivateKey": "必須輸入有效 PGP 私鑰", + "components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey": "必須輸入有效 PGP 公鑰", + "components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey": "PGP 公鑰", + "components.RequestList.RequestItem.cancelRequest": "取消請求", + "components.NotificationTypeSelector.notificationTypes": "通知類型", + "components.Discover.noRequests": "沒有請求。", + "components.Layout.VersionStatus.commitsbehind": "落後 {commitsBehind} 次提交", + "components.Layout.VersionStatus.outofdate": "過時", + "components.Layout.VersionStatus.streamstable": "Overseerr 穩定版", + "components.Layout.VersionStatus.streamdevelop": "Overseerr 開發版", + "components.Settings.SettingsAbout.outofdate": "過時", + "components.Settings.SettingsAbout.uptodate": "最新", + "components.Settings.noDefaultNon4kServer": "如果您只有一個 {serverType} 伺服器,請勿把它設置為 4K 伺服器。", + "components.Settings.noDefaultServer": "您必須至少指定一個 {serverType} 伺服器為默認,才能處理{mediaType}請求。", + "components.Settings.serviceSettingsDescription": "關於 {serverType} 伺服器的設置。{serverType} 伺服器數沒有最大值限制,但您只能指定兩個伺服器為默認(一個非 4K、一個 4K)。", + "components.Settings.mediaTypeSeries": "電視節目", + "components.Settings.mediaTypeMovie": "電影", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "此用戶目前沒有密碼。設置密碼以允許此用戶使用電子郵件地址登錄。", + "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "您的帳戶目前沒有密碼。設置密碼以允許使用電子郵件地址登錄。", + "components.Layout.betawarning": "這是測試版軟體,所以可能會不穩定或被破壞。請向 GitHub 報告問題!", + "components.UserList.autogeneratepasswordTip": "通過電子郵件發送伺服器生成的密碼給用戶" } diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 8847f0ed..efef45f6 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -174,7 +174,11 @@ class MyDocument extends Document { name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> - +
    diff --git a/src/pages/profile/settings/notifications.tsx b/src/pages/profile/settings/notifications.tsx deleted file mode 100644 index dcb27361..00000000 --- a/src/pages/profile/settings/notifications.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { NextPage } from 'next'; -import React from 'react'; -import UserSettings from '../../../components/UserProfile/UserSettings'; -import UserNotificationSettings from '../../../components/UserProfile/UserSettings/UserNotificationSettings'; - -const UserSettingsMainPage: NextPage = () => { - return ( - - - - ); -}; - -export default UserSettingsMainPage; diff --git a/src/pages/profile/settings/notifications/discord.tsx b/src/pages/profile/settings/notifications/discord.tsx new file mode 100644 index 00000000..06e580ff --- /dev/null +++ b/src/pages/profile/settings/notifications/discord.tsx @@ -0,0 +1,17 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsDiscord from '../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord'; + +const NotificationsPage: NextPage = () => { + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/pages/profile/settings/notifications/email.tsx b/src/pages/profile/settings/notifications/email.tsx new file mode 100644 index 00000000..370258ca --- /dev/null +++ b/src/pages/profile/settings/notifications/email.tsx @@ -0,0 +1,17 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsEmail from '../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail'; + +const NotificationsPage: NextPage = () => { + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/pages/profile/settings/notifications/telegram.tsx b/src/pages/profile/settings/notifications/telegram.tsx new file mode 100644 index 00000000..3a641aab --- /dev/null +++ b/src/pages/profile/settings/notifications/telegram.tsx @@ -0,0 +1,17 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsTelegram from '../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram'; + +const NotificationsPage: NextPage = () => { + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/pages/users/[userId]/settings/notifications.tsx b/src/pages/users/[userId]/settings/notifications.tsx deleted file mode 100644 index 08d9d62f..00000000 --- a/src/pages/users/[userId]/settings/notifications.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { NextPage } from 'next'; -import React from 'react'; -import UserSettings from '../../../../components/UserProfile/UserSettings'; -import UserNotificationSettings from '../../../../components/UserProfile/UserSettings/UserNotificationSettings'; -import useRouteGuard from '../../../../hooks/useRouteGuard'; -import { Permission } from '../../../../hooks/useUser'; - -const UserSettingsMainPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); - return ( - - - - ); -}; - -export default UserSettingsMainPage; diff --git a/src/pages/users/[userId]/settings/notifications/discord.tsx b/src/pages/users/[userId]/settings/notifications/discord.tsx new file mode 100644 index 00000000..f24b0810 --- /dev/null +++ b/src/pages/users/[userId]/settings/notifications/discord.tsx @@ -0,0 +1,20 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsDiscord from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord'; +import useRouteGuard from '../../../../../hooks/useRouteGuard'; +import { Permission } from '../../../../../hooks/useUser'; + +const NotificationsPage: NextPage = () => { + useRouteGuard(Permission.MANAGE_USERS); + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/pages/users/[userId]/settings/notifications/email.tsx b/src/pages/users/[userId]/settings/notifications/email.tsx new file mode 100644 index 00000000..7e62b127 --- /dev/null +++ b/src/pages/users/[userId]/settings/notifications/email.tsx @@ -0,0 +1,20 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsEmail from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail'; +import useRouteGuard from '../../../../../hooks/useRouteGuard'; +import { Permission } from '../../../../../hooks/useUser'; + +const NotificationsPage: NextPage = () => { + useRouteGuard(Permission.MANAGE_USERS); + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/pages/users/[userId]/settings/notifications/telegram.tsx b/src/pages/users/[userId]/settings/notifications/telegram.tsx new file mode 100644 index 00000000..d26ad8b4 --- /dev/null +++ b/src/pages/users/[userId]/settings/notifications/telegram.tsx @@ -0,0 +1,20 @@ +import { NextPage } from 'next'; +import React from 'react'; +import UserSettings from '../../../../../components/UserProfile/UserSettings'; +import UserNotificationSettings from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings'; +import UserNotificationsTelegram from '../../../../../components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram'; +import useRouteGuard from '../../../../../hooks/useRouteGuard'; +import { Permission } from '../../../../../hooks/useUser'; + +const NotificationsPage: NextPage = () => { + useRouteGuard(Permission.MANAGE_USERS); + return ( + + + + + + ); +}; + +export default NotificationsPage; diff --git a/src/styles/globals.css b/src/styles/globals.css index 9e0dca53..81e75134 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -217,14 +217,6 @@ img.avatar-sm { @apply flex max-w-lg rounded-md shadow-sm; } -.label-required { - @apply text-red-500; -} - -.label-tip { - @apply block text-gray-500; -} - .actions { @apply pt-5 mt-8 text-white border-t border-gray-700; } @@ -241,6 +233,18 @@ label.text-label { @apply sm:mt-2; } +label a { + @apply text-gray-100 transition duration-300 hover:text-white hover:underline; +} + +.label-required { + @apply ml-1 text-red-500; +} + +.label-tip { + @apply block text-gray-500; +} + button, input, select, @@ -338,18 +342,34 @@ input[type='search']::-webkit-search-cancel-button { @apply text-white bg-gray-700 border border-gray-500 rounded-md hover:border-gray-500; } +.react-select-container-dark .react-select__control { + @apply bg-gray-800 border border-gray-700; +} + .react-select-container .react-select__control--is-focused { @apply text-white bg-gray-700 border border-gray-500 rounded-md shadow; } +.react-select-container-dark .react-select__control--is-focused { + @apply bg-gray-800 border-gray-600; +} + .react-select-container .react-select__menu { @apply text-gray-300 bg-gray-700; } +.react-select-container-dark .react-select__menu { + @apply bg-gray-800; +} + .react-select-container .react-select__option--is-focused { @apply text-white bg-gray-600; } +.react-select-container-dark .react-select__option--is-focused { + @apply bg-gray-700; +} + .react-select-container .react-select__indicator-separator { @apply bg-gray-500; } diff --git a/yarn.lock b/yarn.lock index 5fa28a51..91f368f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1071,35 +1071,35 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@commitlint/cli@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-12.0.1.tgz#8960e34e8f1aed8b2ea50f223ee817fdf2264ffb" - integrity sha512-V+cMYNHJOr40XT9Kvz3Vrz1Eh7QE1rjQrUbifawDAqcOrBJFuoXwU2SAcRtYFCSqFy9EhbreQGhZFs8dYb90KA== +"@commitlint/cli@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-12.1.1.tgz#740370e557a8a17f415052821cdd5276ecb0ab98" + integrity sha512-SB67/s6VJ50seoPx/Sr2gj1fMzKrx+udgarecGdr8h43ah+M2e22gjQJ7xHv5KwyPQ+6ug1YOMCL34ubT4zupQ== dependencies: - "@commitlint/format" "^12.0.1" - "@commitlint/lint" "^12.0.1" - "@commitlint/load" "^12.0.1" - "@commitlint/read" "^12.0.1" - "@commitlint/types" "^12.0.1" + "@commitlint/format" "^12.1.1" + "@commitlint/lint" "^12.1.1" + "@commitlint/load" "^12.1.1" + "@commitlint/read" "^12.1.1" + "@commitlint/types" "^12.1.1" get-stdin "8.0.0" lodash "^4.17.19" resolve-from "5.0.0" resolve-global "1.0.0" yargs "^16.2.0" -"@commitlint/config-conventional@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-12.0.1.tgz#7bf3bbf68bda967c5165135ebe8f2055decf1a83" - integrity sha512-1ZhB135lh47zVmf1orwcjxuKuam11fJIH/bdVxW9XiQv8XPwC6iIp19knfl8FcOT78AVBnes1z6EVxgUeP2/4Q== +"@commitlint/config-conventional@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-12.1.1.tgz#73dd3b1a7912138420d248f334f15c94c250bc9e" + integrity sha512-15CqbXMsQiEb0qbzjEHe2OkzaXPYSp7RxaS6KoSVk/4W0QiigquavQ+M0huBZze92h0lMS6Pxoq4AJ5CQ3D+iQ== dependencies: conventional-changelog-conventionalcommits "^4.3.1" -"@commitlint/ensure@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-12.0.1.tgz#0ed5e997026db25eb080559b6e67f55a21eea080" - integrity sha512-XdBq+q1YBBDxWIAEjE3Y1YMbzhUnUuSLAEWD8SU1xsvEpQXWRYwDlMBRkjO7funNWTdL0ZQSkZDzme70imYjbw== +"@commitlint/ensure@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-12.1.1.tgz#bcefc85f7f8a41bb31f67d7a8966e322b47a6e43" + integrity sha512-XEUQvUjzBVQM7Uv8vYz+c7PDukFvx0AvQEyX/V+PaTkCK/xPvexu7FLbFwvypjSt9BPMf+T/rhB1hVmldkd6lw== dependencies: - "@commitlint/types" "^12.0.1" + "@commitlint/types" "^12.1.1" lodash "^4.17.19" "@commitlint/execute-rule@^11.0.0": @@ -1107,36 +1107,36 @@ resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-11.0.0.tgz#3ed60ab7a33019e58d90e2d891b75d7df77b4b4d" integrity sha512-g01p1g4BmYlZ2+tdotCavrMunnPFPhTzG1ZiLKTCYrooHRbmvqo42ZZn4QMStUEIcn+jfLb6BRZX3JzIwA1ezQ== -"@commitlint/execute-rule@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-12.0.1.tgz#5bb2eba929270cafb2bd8191799d8b451de7fb7e" - integrity sha512-JzyweYfZlFLtXpgP+btzSY3YAkGPg61TqUSYQqBr4+5IaVf1FruMm5v4D5eLu9dAJuNKUfHbM3AEfuEPiZ79pg== +"@commitlint/execute-rule@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-12.1.1.tgz#8aad1d46fb78b3199e4ae36debdc93570bf765ea" + integrity sha512-6mplMGvLCKF5LieL7BRhydpg32tm6LICnWQADrWU4S5g9PKi2utNvhiaiuNPoHUXr29RdbNaGNcyyPv8DSjJsQ== -"@commitlint/format@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-12.0.1.tgz#5164e5a9e8592c1983482cbd71e7ea86a645ff1b" - integrity sha512-rF79ipAxR8yFzPzG5tRoEZ//MRkyxCXj4JhpEjtdaCMBAXMssI8uazn3e5D8z4UFgSDe9qOnL0OmQvql7HTMoA== +"@commitlint/format@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-12.1.1.tgz#a6b14f8605171374eecc2c463098d63c127ab7df" + integrity sha512-bTAoOryTFLqls17JTaRwk2WDVOP0NwuG4F/JPK8RaF6DMZNVQTfajkgTxFENNZRnESfau1BvivvEXfUAW2ZsvA== dependencies: - "@commitlint/types" "^12.0.1" + "@commitlint/types" "^12.1.1" chalk "^4.0.0" -"@commitlint/is-ignored@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-12.0.1.tgz#0e59b0524e16300b1d9d62f8c138f083f22ebf9a" - integrity sha512-AplfLn5mX/kWTIiSolcOhTYcgphuGLX8FUr+HmyHBEqUkO36jt0z9caysH47fqU71ePtH63v1DWm+RYQ5RPDjg== +"@commitlint/is-ignored@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-12.1.1.tgz#6075a5cd2dcda7b6ec93322f5dbe2142cfbb3248" + integrity sha512-Sn4fsnWX+wLAJOD/UZeoVruB98te1TyPYRiDEq0MhRJAQIrP+7jE/O3/ass68AAMq00HvH3OK9kt4UBXggcGjA== dependencies: - "@commitlint/types" "^12.0.1" - semver "7.3.4" + "@commitlint/types" "^12.1.1" + semver "7.3.5" -"@commitlint/lint@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-12.0.1.tgz#a88b01c81cb6ca1867bd3d8fd288ba30017c2b7d" - integrity sha512-1lKyRCq4ahJrY+Xxo8LsqCbALeJkodtEfpmYHeA5HpPMnK7lRSplLqOLcTCjoPfd4vO+gl6aDEZN+ow3YGQBOg== +"@commitlint/lint@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-12.1.1.tgz#cdd898af6eadba8f9e71d7f1255b5a479a757078" + integrity sha512-FFFPpku/E0svL1jaUVqosuZJDDWiNWYBlUw5ZEljh3MwWRcoaWtMIX5bseX+IvHpFZsCTAiBs1kCgNulCi0UvA== dependencies: - "@commitlint/is-ignored" "^12.0.1" - "@commitlint/parse" "^12.0.1" - "@commitlint/rules" "^12.0.1" - "@commitlint/types" "^12.0.1" + "@commitlint/is-ignored" "^12.1.1" + "@commitlint/parse" "^12.1.1" + "@commitlint/rules" "^12.1.1" + "@commitlint/types" "^12.1.1" "@commitlint/load@>6.1.1": version "11.0.0" @@ -1151,40 +1151,40 @@ lodash "^4.17.19" resolve-from "^5.0.0" -"@commitlint/load@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-12.0.1.tgz#4d180fc88e5b4cfcb476a245d899f85154137502" - integrity sha512-dX8KdCWn7w0bTkkk3zKQpe9X8vsTRa5EM+1ffF313wCX9b6tGa9vujhEHCkSzKAbbE2tFV64CHZygE7rtlHdIA== +"@commitlint/load@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-12.1.1.tgz#5a7fb8be11e520931d1237c5e8dc401b7cc9c6c1" + integrity sha512-qOQtgNdJRULUQWP9jkpTwhj7aEtnqUtqeUpbQ9rjS+GIUST65HZbteNUX4S0mAEGPWqy2aK5xGd73cUfFSvuuw== dependencies: - "@commitlint/execute-rule" "^12.0.1" - "@commitlint/resolve-extends" "^12.0.1" - "@commitlint/types" "^12.0.1" + "@commitlint/execute-rule" "^12.1.1" + "@commitlint/resolve-extends" "^12.1.1" + "@commitlint/types" "^12.1.1" chalk "^4.0.0" cosmiconfig "^7.0.0" lodash "^4.17.19" resolve-from "^5.0.0" -"@commitlint/message@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-12.0.1.tgz#caff6743db78c30a063809501cf4b835c3ce7fa6" - integrity sha512-fXuoxRC+NT1wEQi6p8oHfT7wvWIRgTk+udlRJnWTjmMpiYzVnMmmZfasdShirWr4TtxQtMyL+5DVgh7Y98kURw== +"@commitlint/message@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-12.1.1.tgz#56eb1dbb561e85e9295380a46ff3b09bc93cac65" + integrity sha512-RakDSLAiOligXjhbLahV8HowF4K75pZIcs0+Ii9Q8Gz5H3DWf1Ngit7alFTWfcbf/+DTjSzVPov5HiwQZPIBUg== -"@commitlint/parse@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-12.0.1.tgz#ba8641f53e15b523808ba2eaa48c1bf0129c91c4" - integrity sha512-7oEGASmzBnHir5jSIR7KephXrKh7rIi9a6RpH1tOT+CIENYvhe8EDtIy29qMt+RLa2LlaPF7YrAgaJRfzG0YDQ== +"@commitlint/parse@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-12.1.1.tgz#3e49d6dc113d59cf266af0db99e320e933108c56" + integrity sha512-nuljIvAbBDr93DgL0wCArftEIhjSghawAwhvrKNV9FFcqAJqfVqitwMxJrNDCQ5pgUMCSKULLOEv+dA0bLlTEQ== dependencies: - "@commitlint/types" "^12.0.1" + "@commitlint/types" "^12.1.1" conventional-changelog-angular "^5.0.11" conventional-commits-parser "^3.0.0" -"@commitlint/read@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-12.0.1.tgz#41f3295ed9f451d4c65223cd37ddd59ef714bddb" - integrity sha512-baa0YeD4QOctEuthLpExQSi9xPiw0kDPfUVHqp8I88iuIXJECeS8S1+1GBiz89e8dLN9zmEE+sN9vtJHdAp9YA== +"@commitlint/read@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-12.1.1.tgz#22a2d7fd1eab5e38b9b262311af28ac42f9a5097" + integrity sha512-1k0CQEoZIdixvmqZRKEcWdj2XiKS7SlizEOJ1SE99Qui5d5FlBey8eaooTGgmpR6zObpIHJehtEPzM3VzUT3qA== dependencies: - "@commitlint/top-level" "^12.0.1" - "@commitlint/types" "^12.0.1" + "@commitlint/top-level" "^12.1.1" + "@commitlint/types" "^12.1.1" fs-extra "^9.0.0" git-raw-commits "^2.0.0" @@ -1198,35 +1198,35 @@ resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/resolve-extends@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-12.0.1.tgz#77509f386e08bd30262ec9a75c783d8f4f028fd2" - integrity sha512-Mvg0GDi/68Cqw893ha8uhxE8myHfPmiSSSi7d1x4VJNR4hoS37lBdX89kyx4i9NPmLfviY2cUJKTyK8ZrFznZw== +"@commitlint/resolve-extends@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-12.1.1.tgz#80a78b0940775d17888dd2985b52f93d93e0a885" + integrity sha512-/DXRt0S0U3o9lq5cc8OL1Lkx0IjW0HcDWjUkUXshAajBIKBYSJB8x/loNCi1krNEJ8SwLXUEFt5OLxNO6wE9yQ== dependencies: import-fresh "^3.0.0" lodash "^4.17.19" resolve-from "^5.0.0" resolve-global "^1.0.0" -"@commitlint/rules@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-12.0.1.tgz#1c81345f468597656141338a493d5e426e44dab9" - integrity sha512-A5O0ubNGugZR9WWxk5IVOLo07lpdUwhG5WkAW2lYpgZ7Z/2U4PLob9b4Ih1eHbQu+gnVeFr91k7F0DrpM7B8EQ== +"@commitlint/rules@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-12.1.1.tgz#d59182a837d2addf301a3a4ef83316ae7e70248f" + integrity sha512-oCcLF/ykcJfhM2DeeaDyrgdaiuKsqIPNocugdPj2WEyhSYqmx1/u18CV96LAtW+WyyiOLCCeiZwiQutx3T5nXg== dependencies: - "@commitlint/ensure" "^12.0.1" - "@commitlint/message" "^12.0.1" - "@commitlint/to-lines" "^12.0.1" - "@commitlint/types" "^12.0.1" + "@commitlint/ensure" "^12.1.1" + "@commitlint/message" "^12.1.1" + "@commitlint/to-lines" "^12.1.1" + "@commitlint/types" "^12.1.1" -"@commitlint/to-lines@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-12.0.1.tgz#586d89b9f9ff99ef93b3c8aa3d77faffbe3ffedc" - integrity sha512-XwcJ1jY7x2fhudzbGMpNQkTSMVrxWrI8bRMbVe3Abuu7RfYpFf7VXAlhtnLfxBoagaK7RxjC2+eRidp/3txQBg== +"@commitlint/to-lines@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-12.1.1.tgz#40fbed1767d637249ce49b311a51909d8361ecf8" + integrity sha512-W23AH2XF5rI27MOAPSSr0TUDoRe7ZbFoRtYhFnPu2MBmcuDA9Tmfd9N5sM2tBXtdE26uq3SazwKqGt1OoGAilQ== -"@commitlint/top-level@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-12.0.1.tgz#9c7efd319a4f8d29001f011ba8b0e21fad6044f6" - integrity sha512-rHdgt7U24GEau2/9i2vEAbksxkBRiVjHj5ECFL5dd0AJOIvaK++vMg4EF/ME0X/1yd9qVTHTNOl2Q4tTFK7VBQ== +"@commitlint/top-level@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-12.1.1.tgz#228df8fc36b6d7ea7ad149badfb6ef53dbc7001d" + integrity sha512-g7uRbr81QEIg+pbii0OkE17Zh/2C/f6dSmiMDVRn1S0+hNHR1bENCh18hVUKcV/qKTUsKkFlhhWXM9mQBfxQJw== dependencies: find-up "^5.0.0" @@ -1235,10 +1235,10 @@ resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-11.0.0.tgz#719cf05fcc1abb6533610a2e0f5dd1e61eac14fe" integrity sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ== -"@commitlint/types@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-12.0.1.tgz#04a0cbb8aa56b7c004f8939c2d1ef8892ec68327" - integrity sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg== +"@commitlint/types@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-12.1.1.tgz#8e651f6af0171cd4f8d464c6c37a7cf63ee071bd" + integrity sha512-+qGH+s2Lo6qwacV2X3/ZypZwaAI84ift+1HBjXdXtI/q0F5NtmXucV3lcQOTviMTNiJhq4qWON2fjci2NItASw== dependencies: chalk "^4.0.0" @@ -1400,58 +1400,51 @@ dependencies: tslib "^2.0.1" -"@formatjs/ecma402-abstract@1.6.3": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.6.3.tgz#f82bd2cf3aa8aaa0f12f9339902942b8d4b96912" - integrity sha512-7ijswObmYXabVy5GvcpKG29jbyJ9rGtFdRBdmdQvoDmMo0PwlOl/L08GtrjA4YWLAZ0j2owb2YrRLGNAvLBk+Q== +"@formatjs/ecma402-abstract@1.6.5": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.6.5.tgz#ab461b6a284278ffe051ddd817537be4092e71be" + integrity sha512-dhRWSoPPw8PhB5tSOEP9Gi5XZNFC2IkfP95Va70ouIuED0wBlsU1WmO4jDHITL7/kSNqvzKFTT+2S+6jHPq6jw== dependencies: tslib "^2.1.0" -"@formatjs/ecma402-abstract@1.6.4": +"@formatjs/ecma402-abstract@^1.2.1": version "1.6.4" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.6.4.tgz#cff5ef03837fb6bae70b16d04940213c17e87884" integrity sha512-ukFjGD9dLsxcD9D5AEshJqQElPQeUAlTALT/lzIV6OcYojyuU81gw/uXDUOrs6XW79jtOJwQDkLqHbCJBJMOTw== dependencies: tslib "^2.1.0" -"@formatjs/ecma402-abstract@^1.2.1": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.2.4.tgz#0f11e0309bc885d53ddc823e36d04d520fda7674" - integrity sha512-5XEuvm+bImBmSFlhbE9FeRQKXWtpt+WIYRsma96bneoNMnUMeCADHJxNNSA5JSY4TlrjVZFHW3jE4HYm10bLbA== +"@formatjs/icu-messageformat-parser@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-1.1.5.tgz#0c0dae9878329a26a4df6c74d1d3a59de08d4df9" + integrity sha512-TZC3Ac6zTZGlkPoOstJpllo0rkI60kYSOcyhv7zXcaqzAxgdY+6WK8D91x1O9Swy5Jk1PUQM1IAMdafxZoz+Zg== dependencies: - tslib "^2.0.1" + "@formatjs/ecma402-abstract" "1.6.5" + "@formatjs/icu-skeleton-parser" "1.1.2" + tslib "^2.1.0" -"@formatjs/icu-messageformat-parser@1.1.2": +"@formatjs/icu-skeleton-parser@1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-1.1.2.tgz#e0d41edcfd031c0627b0f40dfcce5883d765df5d" - integrity sha512-AgwoQ2XUL+bQ/v7t4TBJh9vsob8zXgfM3RNe3MvJBCVOEZ+9z8mszsqeae/DmJgLK6SDezJex5O9Vdiny58Pwg== + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.1.2.tgz#b559f32a920ea6600df53735143b59e6cc087c1d" + integrity sha512-R0hxPsnq9oOW50HnqKjzuqzUOEUWRdSqqt2wvLCwlFMEx6+MsLW35yzbB9fnxfRZ6vVnYO69TxBfXvvsK2VoUw== dependencies: - "@formatjs/ecma402-abstract" "1.6.4" - "@formatjs/icu-skeleton-parser" "1.1.1" + "@formatjs/ecma402-abstract" "1.6.5" tslib "^2.1.0" -"@formatjs/icu-skeleton-parser@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.1.1.tgz#b2c39a7817816d68d31272947dded970f6d1d1c7" - integrity sha512-hkRJhjr9G0IE730Kxwq65+rz/2fdCckSJTPrKmViMxLNtRmIt6Hx67tffElr9/QSlpzGlXw9XAMdFOa1ylRrJQ== +"@formatjs/intl-displaynames@4.0.13": + version "4.0.13" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-4.0.13.tgz#48ed7a8c25e082ee93d3042d5a73c7c836c53503" + integrity sha512-CESUtkEG0irEtU42zcz1iyN4epExeyqqlnD2UnmiL0xBzpFcUK0qnAGVGC5x6zSL5IQFaod/SXFUtjuO1xdYzQ== dependencies: - "@formatjs/ecma402-abstract" "1.6.4" + "@formatjs/ecma402-abstract" "1.6.5" tslib "^2.1.0" -"@formatjs/intl-displaynames@4.0.11": - version "4.0.11" - resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-4.0.11.tgz#7872625234c15f6e9ab91473a6de1ab26def1fda" - integrity sha512-e3917+HmXStxb2fNP3sOr3R1DMALdWrUteBb3nerA2AKa12mXwmL0lDavrdltwZWqF7/Egh8fF/esB0Z/fqOgQ== +"@formatjs/intl-listformat@5.0.14": + version "5.0.14" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-5.0.14.tgz#20862c464841dc4c46893db9144f3da5e9dc304e" + integrity sha512-umdoZw3ERhAiJ/IUDprNvbmv8/uOZJbZYsdI45pgURIk9mlgiZ1Dysn+FdBF3T+3FW1iFginfCaIwofNXwB2AQ== dependencies: - "@formatjs/ecma402-abstract" "1.6.3" - tslib "^2.1.0" - -"@formatjs/intl-listformat@5.0.12": - version "5.0.12" - resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-5.0.12.tgz#da0daa1988bc753be915e5361b7c237a3bca314e" - integrity sha512-xWAndG73lqJ1+ar6SljCpM9nUsi2YoZfKi45F2YZRSxtUx4JbWYkhpbroOwxjCQ8ppZFoPc2mlLZjhPZiTyG7g== - dependencies: - "@formatjs/ecma402-abstract" "1.6.3" + "@formatjs/ecma402-abstract" "1.6.5" tslib "^2.1.0" "@formatjs/intl-numberformat@^5.5.2": @@ -1461,17 +1454,17 @@ dependencies: "@formatjs/ecma402-abstract" "^1.2.1" -"@formatjs/intl@1.8.4": - version "1.8.4" - resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-1.8.4.tgz#66418092611777f050ab99ba5fe66b89dbcbd846" - integrity sha512-m0/5ZRQZZfzXmeDieoG8kxu3QRvJazv2VbXhROs5khJKfUKu1rz6xfuUrh3gkmydWYtHuwJDIoC9oGR0ik4+/g== +"@formatjs/intl@1.9.8": + version "1.9.8" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-1.9.8.tgz#594ef2430b4c3371d9e3e5a90f1701af58dfda47" + integrity sha512-bED79kr3ENFSxUdWHEDCmeff74EH/l8OViU2T5xIC5XWRqYlwfMxD2vmb04EQZsfmVXUNzZ/2cUBRjhEWcEqPw== dependencies: - "@formatjs/ecma402-abstract" "1.6.3" - "@formatjs/intl-displaynames" "4.0.11" - "@formatjs/intl-listformat" "5.0.12" + "@formatjs/ecma402-abstract" "1.6.5" + "@formatjs/icu-messageformat-parser" "1.1.5" + "@formatjs/intl-displaynames" "4.0.13" + "@formatjs/intl-listformat" "5.0.14" fast-memoize "^2.5.2" - intl-messageformat "9.5.3" - intl-messageformat-parser "6.4.3" + intl-messageformat "9.6.7" tslib "^2.1.0" "@formatjs/ts-transformer@2.13.0": @@ -1483,12 +1476,12 @@ tslib "^2.0.1" typescript "^4.0" -"@formatjs/ts-transformer@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.3.4.tgz#c15b1934efc046a3aec3fd6b869bc4e694cfd397" - integrity sha512-XAXGBGTFfmVPsMDIcFjHYOa9kpEcrhy88rTOAv51Q7gMIK1uW48Ws1jQcvfBxLN32WVFM+1xlfNb8PnL9Qb8sQ== +"@formatjs/ts-transformer@3.3.7": + version "3.3.7" + resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.3.7.tgz#ce480366366195f71a588c863378b0e965e18f41" + integrity sha512-njO4HMo0zGETY5cYz2ifsEO5FnZs+NyIUSXrGrcE0l9p188P5AIsJ+9HeK3ZGP6u/srtchBytIQFrvhskaQOzQ== dependencies: - "@formatjs/icu-messageformat-parser" "1.1.2" + "@formatjs/icu-messageformat-parser" "1.1.5" tslib "^2.1.0" typescript "^4.0" @@ -1535,10 +1528,10 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== -"@headlessui/react@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-0.3.1.tgz#62d8df3b49f7e212f81f7fa4ba3cefb8945720ec" - integrity sha512-GnAVXCLmDs3CFvmvYo4Iu/LqAWVIoS+bGo+eMADnbWgF8BeMX13sWMyb8eOdj7N9nqY9QA2AsMzqYdAIbbsRIw== +"@headlessui/react@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.0.0.tgz#661b50ebfd25041abb45d8eedd85e7559056bcaf" + integrity sha512-mjqRJrgkbcHQBfAHnqH0yRxO/y/22jYrdltpE7WkurafREKZ+pj5bPBwYHMt935Sdz/n16yRcVmsSCqDFHee9A== "@iarna/cli@^1.2.0": version "1.2.0" @@ -1587,20 +1580,20 @@ semver "^7.3.4" tar "^6.1.0" -"@next/env@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@next/env/-/env-10.1.2.tgz#04888eb7115a5b0633dc59e321e5c952917a39d5" - integrity sha512-G6kEq7dr7f+unVTUL74lIaB6njB73vEMVi7AhujaNnNZr6z8jQ43jCjNyawQsNyoNWsRo/9x6x9W72PbrGmy/w== +"@next/env@10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@next/env/-/env-10.1.3.tgz#29e5d62919b4a7b1859f8d36169848dc3f5ddebe" + integrity sha512-q7z7NvmRs66lCQmVJtKjDxVtMTjSwP6ExVzaH46pbTH60MHgzEJ9H4jXrFLTihPmCIvpAv6Ai04jbS8dcg1ZMQ== -"@next/polyfill-module@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-10.1.2.tgz#0cad99af18da0f90a63a25b60602ab46650017e6" - integrity sha512-9+xXb33HIPCrV0yM79blqwgLa+fkvm0gYs/wUDI0pPBCHkMpCZA/SWUeF/yKDY6qWO79H3B5pWTziLmzycQPWA== +"@next/polyfill-module@10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-10.1.3.tgz#beafe89bc4235d436fa0ed02c9d2a5d311fb0238" + integrity sha512-1DtUVcuoBJAn5IrxIZQjUG1KTPkiXMYloykPSkRxawimgvG9dRj2kscU+4KGNSFxHoxW9c68VRCb+7MDz5aGGw== -"@next/react-dev-overlay@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-10.1.2.tgz#e98edfdc7fbed4d0cb333594469c7fa62f96e6df" - integrity sha512-B81nhgkWr+MbDAXN9I38WIdhAKayfIzrnOXXF2MS4VgxyHBvYQQfmobNNE0XBByyDn0+Ww5s9xg3L6Shh9kWKA== +"@next/react-dev-overlay@10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-10.1.3.tgz#ee1c6033b29be9b383e061bd9705021d131ea445" + integrity sha512-vIgUah3bR9+MKzwU1Ni5ONfYM0VdI42i7jZ+Ei1c0wjwkG9anVnDqhSQ3mVg62GP2nt7ExaaFyf9THbsw5KYXg== dependencies: "@babel/code-frame" "7.12.11" anser "1.4.9" @@ -1614,10 +1607,10 @@ stacktrace-parser "0.1.10" strip-ansi "6.0.0" -"@next/react-refresh-utils@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.1.2.tgz#1c60150bb3f004fb9dd02db387a952483e6e2e4c" - integrity sha512-SQvtCt6nNOkGKddidQehxtJKMkoapg/kbLy/HwrqU8WdVrVVAk8JQw/QjDHVEsdezRxspeNKbho4L+3jl4c9rw== +"@next/react-refresh-utils@10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.1.3.tgz#65b3e1b9846c02452787fde1d54ad9c54b506dbd" + integrity sha512-P4GJZuLKfD/o42JvGZ/xP4Hxg68vd3NeZxOLqIuQKFjjaYgC2IrO+lE5PTwGmRkytjfprJC+9j7Jss/xQAS6QA== "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents": version "2.1.8-no-fsevents" @@ -2030,15 +2023,15 @@ lodash.merge "^4.6.2" lodash.uniq "^4.5.0" -"@tanem/react-nprogress@^3.0.60": - version "3.0.60" - resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-3.0.60.tgz#8eefc814a731fbde4605695864319e9bb3824dd2" - integrity sha512-TXtn+D9zKWqbbYct/VdC9fB9zG3IYe5/KH34IOVRjg1JPLyy9va7Cse7zBvNz0OVf2TzRtojkR9Gkd2QxqyFUw== +"@tanem/react-nprogress@^3.0.62": + version "3.0.62" + resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-3.0.62.tgz#07f447d9d4c5915804aa1f30a71d53967f67b8a0" + integrity sha512-8Smqc3+sUlTdSu0gMKJX8T7+ahsJvma/tbka+ZS16cgRgd4x/0usEgmAYIQ6M72D8cqKM7jKheOGGXJkM4GVkA== dependencies: "@babel/runtime" "^7.13.10" hoist-non-react-statics "^3.3.2" prop-types "^15.7.2" - react-use "^17.2.1" + react-use "^17.2.3" "@tootallnate/once@1": version "1.1.2" @@ -2078,10 +2071,10 @@ dependencies: "@babel/types" "^7.3.0" -"@types/bcrypt@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-3.0.0.tgz#851489a9065a067cb7f3c9cbe4ce9bed8bba0876" - integrity sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ== +"@types/bcrypt@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-3.0.1.tgz#9c767594e31aa1c4ce78d23aa4351984403ca28f" + integrity sha512-SwBrq5wb6jXP0o3O3jStdPWbKpimTImfdFD/OZE3uW+jhGpds/l5wMX9lfYOTDOa5Bod2QmOgo9ln+tMp2XP/w== "@types/body-parser@*", "@types/body-parser@^1.19.0": version "1.19.0" @@ -2115,10 +2108,10 @@ resolved "https://registry.yarnpkg.com/@types/country-flag-icons/-/country-flag-icons-1.2.0.tgz#5d13276405a5701ca29bbd7f1026f45c0d2962be" integrity sha512-96aveJfAw9iSfBxAD8DCgFYjMFmLIGa+vBvg3cKiHjX+o4Szz5HHv2DSbEVm9a4kLixsYkioGB4SnJs17Zypzw== -"@types/csurf@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@types/csurf/-/csurf-1.11.0.tgz#2809e89f55f12a2df8cd2826c06dfd66600dd14d" - integrity sha512-IwqGRWImcbIdwumGprYR0EgIZ7GAklOIGaNqe2u7jb0YUilg7yrrxXth11VA/AJK8wQWYHxTQagkCE75oaoBvQ== +"@types/csurf@^1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@types/csurf/-/csurf-1.11.1.tgz#ebdf5fa09a6cfe0258957e0826d3831e464d2697" + integrity sha512-GIdkIfC6/2k+NJdyALSSJ3ek01SPosqMmSdDvWkYY2x7ZR4dgN3G8Xcn+W36l+wiTNM+VHdwdyigXpbetiMC0A== dependencies: "@types/express-serve-static-core" "*" @@ -2127,10 +2120,10 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.31.tgz#bac8d8aab6a823e91deb7f79083b2a35fa638f33" integrity sha512-LS1MCPaQKqspg7FvexuhmDbWUhE2yIJ+4AgVIyObfc06/UKZ8REgxGNjZc82wPLWmbeOm7S+gSsLgo75TanG4A== -"@types/email-templates@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@types/email-templates/-/email-templates-8.0.2.tgz#e677e8400d0a639d1bfb0be546a225c27be5aedd" - integrity sha512-AmhvY1odkpbNyoltbmhYDxTuCRa9wLKdZfng6ijJ4Y/LJ4lUjP4jK4GORIaazd/TOwY5oFnZVcM606aO72Nu0g== +"@types/email-templates@^8.0.3": + version "8.0.3" + resolved "https://registry.yarnpkg.com/@types/email-templates/-/email-templates-8.0.3.tgz#b0ba6816871821feec5d8e2dcab32510fd6aedc0" + integrity sha512-OeLtrRD33up4aihl75fkniqvYi4Gl9tsl3Mx3o+17R2ePdyvULkLuAEcdEEFZ90iVMhuc2ByAaEOjbaF9o5aog== dependencies: "@types/html-to-text" "*" "@types/nodemailer" "*" @@ -2221,6 +2214,13 @@ dependencies: "@types/node" "*" +"@types/hast@^2.0.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9" + integrity sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q== + dependencies: + "@types/unist" "*" + "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -2259,7 +2259,7 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008" integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q== -"@types/mdast@^3.0.0", "@types/mdast@^3.0.3": +"@types/mdast@^3.0.0": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw== @@ -2300,10 +2300,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.34.tgz#07935194fc049069a1c56c0c274265abeddf88da" integrity sha512-dBPaxocOK6UVyvhbnpFIj2W+S+1cBTkHQbFQfeeJhoKFbzYcVUGHvddeWPSucKATb3F0+pgDq0i6ghEaZjsugA== -"@types/node@^14.14.37": - version "14.14.37" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" - integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw== +"@types/node@^14.14.41": + version "14.14.41" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615" + integrity sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g== "@types/nodemailer@*", "@types/nodemailer@^6.4.1": version "6.4.1" @@ -2349,10 +2349,10 @@ dependencies: "@types/react" "*" -"@types/react-select@^4.0.13": - version "4.0.13" - resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-4.0.13.tgz#8d2c41a0df7fbf67ab0b995797b0e9b4e6b38cde" - integrity sha512-rXYEc565IzzjgQzs9C0YCFxV/QajMZnCHG5QwRQ5BZMfH0Lj90VI/xohawemRkD46IvpaLRbO6xzSquJlgBGUA== +"@types/react-select@^4.0.15": + version "4.0.15" + resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-4.0.15.tgz#2e6a1cff22c4bbae6c95b8dbee5b5097c12eae54" + integrity sha512-GPyBFYGMVFCtF4eg9riodEco+s2mflR10Nd5csx69+bcdvX6Uo9H/jgrIqovBU9yxBppB9DS66OwD6xxgVqOYQ== dependencies: "@emotion/serialize" "^1.0.0" "@types/react" "*" @@ -2460,13 +2460,13 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== -"@typescript-eslint/eslint-plugin@^4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.20.0.tgz#9d8794bd99aad9153092ad13c96164e3082e9a92" - integrity sha512-sw+3HO5aehYqn5w177z2D82ZQlqHCwcKSMboueo7oE4KU9QiC0SAgfS/D4z9xXvpTc8Bt41Raa9fBR8T2tIhoQ== +"@typescript-eslint/eslint-plugin@^4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz#3d5f29bb59e61a9dba1513d491b059e536e16dbc" + integrity sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA== dependencies: - "@typescript-eslint/experimental-utils" "4.20.0" - "@typescript-eslint/scope-manager" "4.20.0" + "@typescript-eslint/experimental-utils" "4.22.0" + "@typescript-eslint/scope-manager" "4.22.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -2474,53 +2474,53 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.20.0.tgz#a8ab2d7b61924f99042b7d77372996d5f41dc44b" - integrity sha512-sQNlf6rjLq2yB5lELl3gOE7OuoA/6IVXJUJ+Vs7emrQMva14CkOwyQwD7CW+TkmOJ4Q/YGmoDLmbfFrpGmbKng== +"@typescript-eslint/experimental-utils@4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz#68765167cca531178e7b650a53456e6e0bef3b1f" + integrity sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.20.0" - "@typescript-eslint/types" "4.20.0" - "@typescript-eslint/typescript-estree" "4.20.0" + "@typescript-eslint/scope-manager" "4.22.0" + "@typescript-eslint/types" "4.22.0" + "@typescript-eslint/typescript-estree" "4.22.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.20.0.tgz#8dd403c8b4258b99194972d9799e201b8d083bdd" - integrity sha512-m6vDtgL9EABdjMtKVw5rr6DdeMCH3OA1vFb0dAyuZSa3e5yw1YRzlwFnm9knma9Lz6b2GPvoNSa8vOXrqsaglA== +"@typescript-eslint/parser@^4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.0.tgz#e1637327fcf796c641fe55f73530e90b16ac8fe8" + integrity sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q== dependencies: - "@typescript-eslint/scope-manager" "4.20.0" - "@typescript-eslint/types" "4.20.0" - "@typescript-eslint/typescript-estree" "4.20.0" + "@typescript-eslint/scope-manager" "4.22.0" + "@typescript-eslint/types" "4.22.0" + "@typescript-eslint/typescript-estree" "4.22.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.20.0.tgz#953ecbf3b00845ece7be66246608be9d126d05ca" - integrity sha512-/zm6WR6iclD5HhGpcwl/GOYDTzrTHmvf8LLLkwKqqPKG6+KZt/CfSgPCiybshmck66M2L5fWSF/MKNuCwtKQSQ== +"@typescript-eslint/scope-manager@4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz#ed411545e61161a8d702e703a4b7d96ec065b09a" + integrity sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q== dependencies: - "@typescript-eslint/types" "4.20.0" - "@typescript-eslint/visitor-keys" "4.20.0" + "@typescript-eslint/types" "4.22.0" + "@typescript-eslint/visitor-keys" "4.22.0" "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== -"@typescript-eslint/types@4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.20.0.tgz#c6cf5ef3c9b1c8f699a9bbdafb7a1da1ca781225" - integrity sha512-cYY+1PIjei1nk49JAPnH1VEnu7OYdWRdJhYI5wiKOUMhLTG1qsx5cQxCUTuwWCmQoyriadz3Ni8HZmGSofeC+w== +"@typescript-eslint/types@4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.0.tgz#0ca6fde5b68daf6dba133f30959cc0688c8dd0b6" + integrity sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA== -"@typescript-eslint/typescript-estree@4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.20.0.tgz#8b3b08f85f18a8da5d88f65cb400f013e88ab7be" - integrity sha512-Knpp0reOd4ZsyoEJdW8i/sK3mtZ47Ls7ZHvD8WVABNx5Xnn7KhenMTRGegoyMTx6TiXlOVgMz9r0pDgXTEEIHA== +"@typescript-eslint/typescript-estree@4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz#b5d95d6d366ff3b72f5168c75775a3e46250d05c" + integrity sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg== dependencies: - "@typescript-eslint/types" "4.20.0" - "@typescript-eslint/visitor-keys" "4.20.0" + "@typescript-eslint/types" "4.22.0" + "@typescript-eslint/visitor-keys" "4.22.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -2548,12 +2548,12 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@typescript-eslint/visitor-keys@4.20.0": - version "4.20.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.20.0.tgz#1e84db034da13f208325e6bfc995c3b75f7dbd62" - integrity sha512-NXKRM3oOVQL8yNFDNCZuieRIwZ5UtjNLYtmMx2PacEAGmbaEYtGgVHUHVyZvU/0rYZcizdrWjDo+WBtRPSgq+A== +"@typescript-eslint/visitor-keys@4.22.0": + version "4.22.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz#169dae26d3c122935da7528c839f42a8a42f6e47" + integrity sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw== dependencies: - "@typescript-eslint/types" "4.20.0" + "@typescript-eslint/types" "4.22.0" eslint-visitor-keys "^2.0.0" "@xobotyi/scrollbar-width@^1.9.5": @@ -3759,7 +3759,7 @@ cheerio@^1.0.0-rc.3: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@3.5.1: +chokidar@3.5.1, chokidar@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== @@ -4106,6 +4106,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -5060,6 +5065,11 @@ dir-glob@^3.0.0, dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -5151,13 +5161,6 @@ domhandler@^3.0.0: dependencies: domelementtype "^2.0.1" -domhandler@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a" - integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA== - dependencies: - domelementtype "^2.0.1" - domhandler@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e" @@ -5190,15 +5193,6 @@ domutils@^2.0.0: domelementtype "^2.0.1" domhandler "^3.0.0" -domutils@^2.4.2: - version "2.4.4" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.4.4.tgz#282739c4b150d022d34699797369aad8d19bbbd3" - integrity sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils@^2.4.4: version "2.5.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.0.tgz#42f49cffdabb92ad243278b331fd761c1c2d3039" @@ -5533,18 +5527,18 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -eslint-config-prettier@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz#4ef1eaf97afe5176e6a75ddfb57c335121abc5a6" - integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw== +eslint-config-prettier@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.2.0.tgz#78de77d63bca8e9e59dae75a614b5299925bb7b3" + integrity sha512-dWV9EVeSo2qodOPi1iBYU/x6F6diHv8uujxbxr77xExs3zTAlNXvVZKiyLsQGNz7yPV2K49JY5WjPzNIuDc2Bw== -eslint-plugin-formatjs@^2.14.3: - version "2.14.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-formatjs/-/eslint-plugin-formatjs-2.14.3.tgz#9b4bb293a4410a73f6a8eadf769276323155f3fe" - integrity sha512-OGYyEIt4RhflcPrY3xwmlpc61l2pmuJSVUErsKXp3syyUiYBynfmlUoskCDFvGrFHwtYvBUoW2XoEaTc6D/msg== +eslint-plugin-formatjs@^2.14.6: + version "2.14.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-formatjs/-/eslint-plugin-formatjs-2.14.6.tgz#2cc59f6a905ff1d04b9c9d92e89e5aa0fe0e6d76" + integrity sha512-+FQ+AD8dumAmuWHM0HoOqFHcmfSv+Ag3cQ73LH/6QRIX8AZiZbdc4oV3ZDHRaE9dQtp54L1VJhmi8TEsHGjzHQ== dependencies: - "@formatjs/icu-messageformat-parser" "1.1.2" - "@formatjs/ts-transformer" "3.3.4" + "@formatjs/icu-messageformat-parser" "1.1.5" + "@formatjs/ts-transformer" "3.3.7" "@types/emoji-regex" "^8.0.0" "@types/eslint" "^7.2.0" "@typescript-eslint/typescript-estree" "^3.6.0" @@ -5568,10 +5562,10 @@ eslint-plugin-jsx-a11y@^6.4.1: jsx-ast-utils "^3.1.0" language-tags "^1.0.5" -eslint-plugin-prettier@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz#7079cfa2497078905011e6f82e8dd8453d1371b7" - integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ== +eslint-plugin-prettier@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" + integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== dependencies: prettier-linter-helpers "^1.0.0" @@ -5580,10 +5574,10 @@ eslint-plugin-react-hooks@^4.2.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== -eslint-plugin-react@^7.23.1: - version "7.23.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.23.1.tgz#f1a2e844c0d1967c822388204a8bc4dee8415b11" - integrity sha512-MvFGhZjI8Z4HusajmSw0ougGrq3Gs4vT/0WgwksZgf5RrLrRa2oYAw56okU4tZJl8+j7IYNuTM+2RnFEuTSdRQ== +eslint-plugin-react@^7.23.2: + version "7.23.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.23.2.tgz#2d2291b0f95c03728b55869f01102290e792d494" + integrity sha512-AfjgFQB+nYszudkxRkTFu0UR1zEQig0ArVMPloKhxwlwkzaw/fBiH0QWcBBhZONlXqQC51+nfqFrkn4EzHcGBw== dependencies: array-includes "^3.1.3" array.prototype.flatmap "^1.2.4" @@ -5623,10 +5617,10 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.23.0: - version "7.23.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.23.0.tgz#8d029d252f6e8cf45894b4bee08f5493f8e94325" - integrity sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q== +eslint@^7.24.0: + version "7.24.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a" + integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ== dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.0" @@ -5799,10 +5793,10 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -express-openapi-validator@^4.12.6: - version "4.12.6" - resolved "https://registry.yarnpkg.com/express-openapi-validator/-/express-openapi-validator-4.12.6.tgz#0738a0f7b8fb643839dd8c4a5f95809cb2d51f08" - integrity sha512-F8m1Kp2zNhwGq2a/cu5PJgZkIQs5WyH68nSxH0uIOoHmDF8PPixp2xEtuQVtj/XQeAtBT7Em+7q7GT7ASGjXzg== +express-openapi-validator@^4.12.7: + version "4.12.7" + resolved "https://registry.yarnpkg.com/express-openapi-validator/-/express-openapi-validator-4.12.7.tgz#af7635d5c1890aa749d12bbfa786700e99eb33fa" + integrity sha512-W9IWH7P3L/2NYubhpfXbT2lt1i+U7ZMmAt/UDLn5xDfMYxl7zlXo7LtjcO0hOItYGicFLgQleBsw9cNHDZBkug== dependencies: "@types/multer" "^1.4.5" ajv "^6.12.6" @@ -5968,6 +5962,18 @@ fast-glob@^3.1.1: micromatch "^4.0.2" picomatch "^2.2.1" +fast-glob@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" + integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -6507,6 +6513,21 @@ git-raw-commits@^2.0.0: split2 "^2.0.0" through2 "^3.0.0" +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -6852,16 +6873,6 @@ html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -html-to-react@^1.3.4: - version "1.4.5" - resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.5.tgz#59091c11021d1ef315ef738460abb6a4a41fe1ce" - integrity sha512-KONZUDFPg5OodWaQu2ymfkDmU0JA7zB1iPfvyHehTmMUZnk0DS7/TyCMTzsLH6b4BvxX15g88qZCXFhJWktsmA== - dependencies: - domhandler "^3.3.0" - htmlparser2 "^5.0" - lodash.camelcase "^4.3.0" - ramda "^0.27.1" - html-to-text@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-7.0.0.tgz#97ff0bcf34241c282f78f5c1baa05dfa44d9d3c3" @@ -6905,16 +6916,6 @@ htmlparser2@^4.0.0, htmlparser2@^4.1.0: domutils "^2.0.0" entities "^2.0.0" -htmlparser2@^5.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-5.0.1.tgz#7daa6fc3e35d6107ac95a4fc08781f091664f6e7" - integrity sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ== - dependencies: - domelementtype "^2.0.1" - domhandler "^3.3.0" - domutils "^2.4.2" - entities "^2.0.0" - htmlparser2@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.0.1.tgz#422521231ef6d42e56bd411da8ba40aa36e91446" @@ -7199,6 +7200,11 @@ init-package-json@^1.10.3: validate-npm-package-license "^3.0.1" validate-npm-package-name "^3.0.0" +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + inline-style-prefixer@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.0.tgz#f73d5dbf2855733d6b153a4d24b7b47a73e9770b" @@ -7250,14 +7256,6 @@ intl-messageformat-parser@6.1.2: "@formatjs/ecma402-abstract" "1.5.0" tslib "^2.0.1" -intl-messageformat-parser@6.4.3: - version "6.4.3" - resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-6.4.3.tgz#4326201256c52907f342c7bb058208113c3c7f95" - integrity sha512-gpB7OeKDSd9wqjIQ7wVQM9byrpMlokGoUfJND7DS9SjoBbOsZIHAHw+lrmAWYmq+MI3WQUeLouSFdYAZ6zSX9A== - dependencies: - "@formatjs/ecma402-abstract" "1.6.3" - tslib "^2.1.0" - intl-messageformat-parser@^5.3.7: version "5.5.1" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-5.5.1.tgz#f09a692755813e6220081e3374df3fb1698bd0c6" @@ -7265,13 +7263,13 @@ intl-messageformat-parser@^5.3.7: dependencies: "@formatjs/intl-numberformat" "^5.5.2" -intl-messageformat@9.5.3: - version "9.5.3" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.5.3.tgz#cb89a91cc2da875c5c824d374ba8209fac63a3ca" - integrity sha512-Ei8vH41/icJsc16ZfWk1FzZ2SpaVn0gElXsQCKKPerxK/28m1gVdH0G26GuCqAyz5ETEJiSRn8sPMaSWJDuTjg== +intl-messageformat@9.6.7: + version "9.6.7" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.6.7.tgz#ce38c8c8903106cce37f0d7ad9595b4e552303e2" + integrity sha512-31+sJcg3txHZSCwTxGXAPXaOxFv+VVvNI42YKBBUHVKmdneEpoXBwqGyUYzzsz9Z10umpUKGEVL3P9DzXO+gOg== dependencies: + "@formatjs/icu-messageformat-parser" "1.1.5" fast-memoize "^2.5.2" - intl-messageformat-parser "6.4.3" tslib "^2.1.0" intl@^1.2.5: @@ -7484,6 +7482,11 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + is-expression@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" @@ -7504,6 +7507,11 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -7531,6 +7539,13 @@ is-generator-function@^1.0.7: resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b" integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ== +is-glob@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -8410,11 +8425,6 @@ lodash._root@~3.0.0: resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - lodash.capitalize@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" @@ -8505,6 +8515,11 @@ lodash.toarray@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= + lodash.union@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" @@ -8757,12 +8772,12 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -mdast-add-list-metadata@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf" - integrity sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA== +mdast-util-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" + integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== dependencies: - unist-util-visit-parents "1.1.2" + unist-util-visit "^2.0.0" mdast-util-from-markdown@^0.8.0: version "0.8.4" @@ -8775,6 +8790,20 @@ mdast-util-from-markdown@^0.8.0: parse-entities "^2.0.0" unist-util-stringify-position "^2.0.0" +mdast-util-to-hast@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.2.0.tgz#61875526a017d8857b71abc9333942700b2d3604" + integrity sha512-JoPBfJ3gBnHZ18icCwHR50orC9kNH81tiR1gs01D8Q5YpV6adHNO9nKNuFBCJQ941/32PT1a63UF/DitmS3amQ== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + mdast-util-definitions "^4.0.0" + mdurl "^1.0.0" + unist-builder "^2.0.0" + unist-util-generated "^1.0.0" + unist-util-position "^3.0.0" + unist-util-visit "^2.0.0" + mdast-util-to-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" @@ -8795,6 +8824,11 @@ mdn-data@2.0.6: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== +mdurl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + meant@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" @@ -9287,17 +9321,17 @@ nerf-dart@^1.0.0: resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" integrity sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo= -next@10.1.2: - version "10.1.2" - resolved "https://registry.yarnpkg.com/next/-/next-10.1.2.tgz#2c508cc2982077f0bad6863be020c10c1d059970" - integrity sha512-S2KYS8NXeFmaJd8EyoC/kWi3uIlNz3PghnpDWYwy5dxhbtyaozK7fVpXmDcOTQEyYq3BZG5ph0B+hOsAwMdYfQ== +next@10.1.3: + version "10.1.3" + resolved "https://registry.yarnpkg.com/next/-/next-10.1.3.tgz#e26e8371343a42bc2ba9be5cb253a7d324d03673" + integrity sha512-8Jf38F+s0YcXXkJGF5iUxOqSmbHrey0fX5Epc43L0uwDKmN2jK9vhc2ihCwXC1pmu8d2m/8wfTiXRJKGti55yw== dependencies: "@babel/runtime" "7.12.5" "@hapi/accept" "5.0.1" - "@next/env" "10.1.2" - "@next/polyfill-module" "10.1.2" - "@next/react-dev-overlay" "10.1.2" - "@next/react-refresh-utils" "10.1.2" + "@next/env" "10.1.3" + "@next/polyfill-module" "10.1.3" + "@next/react-dev-overlay" "10.1.3" + "@next/react-refresh-utils" "10.1.3" "@opentelemetry/api" "0.14.0" assert "2.0.0" ast-types "0.13.2" @@ -10325,6 +10359,16 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -10592,7 +10636,7 @@ postcss-js@^3.0.3: camelcase-css "^2.0.1" postcss "^8.1.6" -postcss-nested@^5.0.5: +postcss-nested@5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.5.tgz#f0a107d33a9fab11d7637205f5321e27223e3603" integrity sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew== @@ -10656,7 +10700,7 @@ postcss@^7.0.32: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.9: +postcss@^8.1.6, postcss@^8.2.1: version "8.2.9" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.9.tgz#fd95ff37b5cee55c409b3fdd237296ab4096fba3" integrity sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q== @@ -10665,6 +10709,15 @@ postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.9: nanoid "^3.1.22" source-map "^0.6.1" +postcss@^8.2.10: + version "8.2.10" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b" + integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.22" + source-map "^0.6.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -10766,6 +10819,13 @@ property-expr@^2.0.4: resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.4.tgz#37b925478e58965031bb612ec5b3260f8241e910" integrity sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg== +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -11034,16 +11094,16 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + qw@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ= -ramda@^0.27.1: - version "0.27.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9" - integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw== - random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" @@ -11144,41 +11204,48 @@ react-intersection-observer@^8.31.0: resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.31.0.tgz#0ed21aaf93c4c0475b22b0ccaba6169076d01605" integrity sha512-XraIC/tkrD9JtrmVA7ypEN1QIpKc52mXBH1u/bz/aicRLo8QQEJQAMUTb8mz4B6dqpPwyzgjrr7Ljv/2ACDtqw== -react-intl@5.13.5: - version "5.13.5" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.13.5.tgz#32bb74120b67950fe63329db58aa83cfac73f6c8" - integrity sha512-Ym6knnC04k070vwe3UDcRHQUDE2rGn1PNfmYNhDHVPL6vbusuFbefjnt8ZC1GEjnfo29WUHn/tkGd9SMudzD+g== +react-intl@5.15.8: + version "5.15.8" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.15.8.tgz#e81ba679e1b751cd6f289e080f7afd2a4d8afc2f" + integrity sha512-dCExVchYckCSdBTaWu23kXuGaPLnbJ0rV/5t1OALNRxuF7YLdV7cATN2Lpl6VDcCewHmCn0QhxJDD3GpsUc/Pg== dependencies: - "@formatjs/ecma402-abstract" "1.6.3" - "@formatjs/intl" "1.8.4" - "@formatjs/intl-displaynames" "4.0.11" - "@formatjs/intl-listformat" "5.0.12" + "@formatjs/ecma402-abstract" "1.6.5" + "@formatjs/icu-messageformat-parser" "1.1.5" + "@formatjs/intl" "1.9.8" + "@formatjs/intl-displaynames" "4.0.13" + "@formatjs/intl-listformat" "5.0.14" "@types/hoist-non-react-statics" "^3.3.1" hoist-non-react-statics "^3.3.2" - intl-messageformat "9.5.3" - intl-messageformat-parser "6.4.3" + intl-messageformat "9.6.7" tslib "^2.1.0" -react-is@16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: +react-is@16.13.1, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-markdown@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-5.0.3.tgz#41040ea7a9324b564b328fb81dd6c04f2a5373ac" - integrity sha512-jDWOc1AvWn0WahpjW6NK64mtx6cwjM4iSsLHJPNBqoAgGOVoIdJMqaKX4++plhOtdd4JksdqzlDibgPx6B/M2w== +react-is@^17.0.0: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-markdown@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-6.0.0.tgz#e63cd32d095e864384d524986c44c34c919de517" + integrity sha512-MC+zljUJeoLb4RbDm/wRbfoQFEZGz4TDOt/wb4dEehdaJWxLMn/T2IgwhQy0VYhuPEd2fhd7iOayE8lmENU0FA== dependencies: - "@types/mdast" "^3.0.3" + "@types/hast" "^2.0.0" "@types/unist" "^2.0.3" - html-to-react "^1.3.4" - mdast-add-list-metadata "1.0.1" + comma-separated-tokens "^1.0.0" prop-types "^15.7.2" - react-is "^16.8.6" + property-information "^5.0.0" + react-is "^17.0.0" remark-parse "^9.0.0" + remark-rehype "^8.0.0" + space-separated-tokens "^1.1.0" + style-to-object "^0.3.0" unified "^9.0.0" unist-util-visit "^2.0.0" - xtend "^4.0.1" react-refresh@0.8.3: version "0.8.3" @@ -11246,10 +11313,10 @@ react-use-clipboard@1.0.7: dependencies: copy-to-clipboard "^3.3.1" -react-use@^17.2.1: - version "17.2.1" - resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.2.1.tgz#c81e12544115ed049c7deba1e3bb3d977dfee9b8" - integrity sha512-9r51/at7/Nr/nEP4CsHz+pl800EAqhIY9R6O68m68kaWc8slDAfx1UrIedQqpsb4ImddFYb+6hF1i5Vj4u4Cnw== +react-use@^17.2.3: + version "17.2.3" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.2.3.tgz#ba3e5711d6ec4d51637641d6db63897e98c5904f" + integrity sha512-cHLG5mwv9NSkydhlY3J1B/Z5gGzRF43QXzFaMisSaFClg0o1VeWJaYj2d9HJIiTGC+imt47FY4TpnZNRhbOyaQ== dependencies: "@types/js-cookie" "^2.2.6" "@xobotyi/scrollbar-width" "^1.9.5" @@ -11585,6 +11652,13 @@ remark-parse@^9.0.0: dependencies: mdast-util-from-markdown "^0.8.0" +remark-rehype@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-8.1.0.tgz#610509a043484c1e697437fa5eb3fd992617c945" + integrity sha512-EbCu9kHgAxKmW1yEYjx3QafMyGY3q8noUbNUI5xyKbaFP89wbhDrKxyIQNukNYthzjNHZu6J7hwFg7hRm1svYA== + dependencies: + mdast-util-to-hast "^10.2.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -11982,10 +12056,10 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.4, semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" @@ -11994,6 +12068,13 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -12302,6 +12383,11 @@ sourcemap-codec@^1.4.8: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +space-separated-tokens@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + spawn-error-forwarder@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz#1afd94738e999b0346d7b9fc373be55e07577029" @@ -12748,6 +12834,13 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +style-to-object@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + styled-jsx@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-3.3.2.tgz#2474601a26670a6049fb4d3f94bd91695b3ce018" @@ -12883,29 +12976,36 @@ table@^6.0.4: slice-ansi "^4.0.0" string-width "^4.2.0" -tailwindcss@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.0.4.tgz#cf13e62738c3a27065664e449d93b66ee2945506" - integrity sha512-WhgR0oiBxGOZ9jY0yVfaJCHnckR7U74Fs/BMsYxGdwGJQ5Hd/HlaKD26bEJFZOvYScJo0QcUj2ImldzedsG7Bw== +tailwindcss@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.1.tgz#642f6038c9283a8e1454da34585b8b7c1a1e8877" + integrity sha512-zZ6axGqpSZOCBS7wITm/WNHkBzDt5CIZlDlx0eCVldwTxFPELCVGbgh7Xpb3/kZp3cUxOmK7bZUjqhuMrbN6xQ== dependencies: "@fullhuman/postcss-purgecss" "^3.1.3" bytes "^3.0.0" chalk "^4.1.0" + chokidar "^3.5.1" color "^3.1.3" detective "^5.2.0" didyoumean "^1.2.1" + dlv "^1.1.3" + fast-glob "^3.2.5" fs-extra "^9.1.0" html-tags "^3.1.0" lodash "^4.17.21" + lodash.topath "^4.5.2" modern-normalize "^1.0.0" node-emoji "^1.8.1" + normalize-path "^3.0.0" object-hash "^2.1.1" + parse-glob "^3.0.4" postcss-functions "^3" postcss-js "^3.0.3" - postcss-nested "^5.0.5" + postcss-nested "5.0.5" postcss-selector-parser "^6.0.4" postcss-value-parser "^4.1.0" pretty-hrtime "^1.0.3" + quick-lru "^5.1.1" reduce-css-calc "^2.1.8" resolve "^1.20.0" @@ -13216,12 +13316,7 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242" - integrity sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg== - -tslib@^2.1.0: +tslib@^2.0.1, tslib@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== @@ -13355,10 +13450,10 @@ typescript@^4.0: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== -typescript@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" - integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== +typescript@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" + integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== uc.micro@^1.0.1: version "1.0.6" @@ -13492,11 +13587,26 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +unist-builder@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" + integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== + +unist-util-generated@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" + integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== + unist-util-is@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.0.4.tgz#3e9e8de6af2eb0039a59f50c9b3e99698a924f50" integrity sha512-3dF39j/u423v4BBQrk1AQ2Ve1FxY5W3JKwXxVFzBODQ6WEvccguhgp802qQLKSnxPODE6WuRZtV+ohlUg4meBA== +unist-util-position@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" + integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== + unist-util-stringify-position@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" @@ -13504,11 +13614,6 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" -unist-util-visit-parents@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz#f6e3afee8bdbf961c0e6f028ea3c0480028c3d06" - integrity sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q== - unist-util-visit-parents@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" @@ -13915,10 +14020,10 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -winston-daily-rotate-file@^4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.1.tgz#5f55e26d5aef0e841041a5ee904496a591741ca0" - integrity sha512-Uv1KeBneTKFZ9R3J6SmI61vOoPEofxS+GZGEwYRPc7QFE1fpEz648eGWxLnOeo8CBrANwsd+GfK5DCd4Ab1xAQ== +winston-daily-rotate-file@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.2.tgz#abe72bc8973dcc294faff54ae9a589180cf92866" + integrity sha512-DpAz9djExzFGVGRIKCKzsjOQaIINbjOUJ8CRsZGz0SQOMMcO1kM7jqTdzQAM9CRTEksZV9bBw9TT0ddQBGxs9g== dependencies: file-stream-rotator "^0.5.7" object-hash "^2.0.1" @@ -14097,15 +14202,15 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + version "3.2.2" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" + integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== y18n@^4.0.0: version "4.0.0"